agora inbox for [email protected]  
help / color / mirror / Atom feed
[PATCH v24 09/15] Add regression tests for Incremental View Maintenance
78+ messages / 3 participants
[nested] [flat]

* [PATCH v28 10/11] Add regression tests for Incremental View Maintenance
@ 2021-03-10 02:11 Takuma Hoshiai <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Takuma Hoshiai @ 2021-03-10 02:11 UTC (permalink / raw)

---
 src/bin/pg_dump/pg_dump.h                     |    1 +
 .../regress/expected/incremental_matview.out  | 1031 +++++++++++++++++
 src/test/regress/parallel_schedule            |    2 +-
 src/test/regress/sql/incremental_matview.sql  |  534 +++++++++
 4 files changed, 1567 insertions(+), 1 deletion(-)
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index 119293a751..c3960a4192 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -322,6 +322,7 @@ typedef struct _tableInfo
 
 	int			numParents;		/* number of (immediate) parent tables */
 	struct _tableInfo **parents;	/* TableInfos of immediate parents */
+
 	bool		isivm;			/* is incrementally maintainable materialized view? */
 
 	/*
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 0000000000..b1e9424508
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1031 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (i int, j int);
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+CREATE TABLE mv_base_b (i int, k int);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS ivm_admin;
+NOTICE:  role "ivm_admin" does not exist, skipping
+DROP USER IF EXISTS ivm_user;
+NOTICE:  role "ivm_user" does not exist, skipping
+CREATE USER ivm_admin;
+CREATE USER ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by ivm_user
+SET SESSION AUTHORIZATION ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |  owner   
+----+------+----------
+  1 | foo  | ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |  owner   
+----+------+----------
+  1 | foo  | ivm_user
+  3 | baz  | ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |  owner   
+----+-------+----------
+  2 | bar   | ivm_user
+  3 | baz   | ivm_user
+  6 | corge | ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |  owner   |   num   
+----+-------+----------+---------
+  2 | bar   | ivm_user | two
+  3 | baz_2 | ivm_user | three_2
+  6 | corge | ivm_user | six
+(3 rows)
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER ivm_user;
+DROP USER ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index cf46fa3359..013f5db7fb 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -78,7 +78,7 @@ test: brin_bloom brin_multi
 # psql depends on create_am
 # amutils depends on geometry, create_index_spgist, hash_index, brin
 # ----------
-test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions sysviews tsrf tid tidscan tidrangescan collate.icu.utf8 incremental_sort create_role
+test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions sysviews tsrf tid tidscan tidrangescan collate.icu.utf8 incremental_sort create_role incremental_matview
 
 # collate.*.utf8 tests cannot be run in parallel with each other
 test: rules psql psql_crosstab amutils stats_ext collate.linux.utf8 collate.windows.win1252
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 0000000000..63e26da767
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,534 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (i int, j int);
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+CREATE TABLE mv_base_b (i int, k int);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS ivm_admin;
+DROP USER IF EXISTS ivm_user;
+CREATE USER ivm_admin;
+CREATE USER ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by ivm_user
+SET SESSION AUTHORIZATION ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER ivm_user;
+DROP USER ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.25.1


--Multipart=_Thu__1_Jun_2023_23_59_09_+0900_/G5+8nG46.f1T42K
Content-Type: text/x-diff;
 name="v28-0011-Add-documentations-about-Incremental-View-Mainte.patch"
Content-Disposition: attachment;
 filename="v28-0011-Add-documentations-about-Incremental-View-Mainte.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v31 10/11] Add regression tests for Incremental View Maintenance
@ 2021-03-10 02:11 Takuma Hoshiai <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Takuma Hoshiai @ 2021-03-10 02:11 UTC (permalink / raw)

---
 .../regress/expected/incremental_matview.out  | 1030 +++++++++++++++++
 src/test/regress/parallel_schedule            |    2 +-
 src/test/regress/sql/incremental_matview.sql  |  533 +++++++++
 3 files changed, 1564 insertions(+), 1 deletion(-)
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 0000000000..8946d09f5d
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1030 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (i int, j int);
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+CREATE TABLE mv_base_b (i int, k int);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS ivm_admin;
+NOTICE:  role "ivm_admin" does not exist, skipping
+DROP USER IF EXISTS ivm_user;
+NOTICE:  role "ivm_user" does not exist, skipping
+CREATE USER ivm_admin;
+CREATE USER ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by ivm_user
+SET SESSION AUTHORIZATION ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |  owner   
+----+------+----------
+  1 | foo  | ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |  owner   
+----+------+----------
+  1 | foo  | ivm_user
+  3 | baz  | ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |  owner   
+----+-------+----------
+  2 | bar   | ivm_user
+  3 | baz   | ivm_user
+  6 | corge | ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |  owner   |   num   
+----+-------+----------+---------
+  2 | bar   | ivm_user | two
+  3 | baz_2 | ivm_user | three_2
+  6 | corge | ivm_user | six
+(3 rows)
+
+-- automatic index creation
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER ivm_user;
+DROP USER ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 5ac6e871f5..64c910af65 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -78,7 +78,7 @@ test: brin_bloom brin_multi
 # psql depends on create_am
 # amutils depends on geometry, create_index_spgist, hash_index, brin
 # ----------
-test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps
+test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 test: rules psql psql_crosstab amutils stats_ext collate.linux.utf8 collate.windows.win1252
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 0000000000..82686f9324
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,533 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (i int, j int);
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+CREATE TABLE mv_base_b (i int, k int);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS ivm_admin;
+DROP USER IF EXISTS ivm_user;
+CREATE USER ivm_admin;
+CREATE USER ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by ivm_user
+SET SESSION AUTHORIZATION ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- automatic index creation
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER ivm_user;
+DROP USER ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.25.1


--Multipart=_Fri__29_Mar_2024_23_47_00_+0900_KGpmmDOIs1266Ib1
Content-Type: text/x-diff;
 name="v31-0011-Add-documentations-about-Incremental-View-Mainte.patch"
Content-Disposition: attachment;
 filename="v31-0011-Add-documentations-about-Incremental-View-Mainte.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v23 09/15] Add regression tests for Incremental View Maintenance
@ 2021-03-10 02:11 Takuma Hoshiai <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Takuma Hoshiai @ 2021-03-10 02:11 UTC (permalink / raw)

---
 .../regress/expected/incremental_matview.out  | 799 ++++++++++++++++++
 src/test/regress/parallel_schedule            |   2 +-
 src/test/regress/sql/incremental_matview.sql  | 400 +++++++++
 3 files changed, 1200 insertions(+), 1 deletion(-)
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 0000000000..fe5bc734e2
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,799 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (i int, j int);
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+CREATE TABLE mv_base_b (i int, k int);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appeared in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- base table which has row level security
+DROP USER IF EXISTS ivm_admin;
+NOTICE:  role "ivm_admin" does not exist, skipping
+DROP USER IF EXISTS ivm_user;
+NOTICE:  role "ivm_user" does not exist, skipping
+CREATE USER ivm_admin;
+CREATE USER ivm_user;
+SET SESSION AUTHORIZATION ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four');
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+CREATE POLICY rls_tbl_policy2 ON rls_tbl FOR INSERT TO PUBLIC WITH CHECK(current_user LIKE 'ivm_%');
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+SET SESSION AUTHORIZATION ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |  owner   
+----+------+----------
+  1 | foo  | ivm_user
+(1 row)
+
+INSERT INTO rls_tbl VALUES
+  (3,'baz','ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |  owner   
+----+------+----------
+  1 | foo  | ivm_user
+  3 | baz  | ivm_user
+(2 rows)
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |  owner   |   num   
+----+-------+----------+---------
+  1 | foo   | ivm_user | one
+  3 | baz_2 | ivm_user | three_2
+(2 rows)
+
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER ivm_user;
+DROP USER ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 7be89178f0..b0350f47dd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -86,7 +86,7 @@ test: brin_bloom brin_multi
 # ----------
 # Another group of parallel tests
 # ----------
-test: create_table_like alter_generic alter_operator misc async dbsize misc_functions sysviews tsrf tid tidscan tidrangescan collate.icu.utf8 incremental_sort
+test: create_table_like alter_generic alter_operator misc async dbsize misc_functions sysviews tsrf tid tidscan tidrangescan collate.icu.utf8 incremental_sort incremental_matview
 
 # rules cannot run concurrently with any test that creates
 # a view or rule in the public schema
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 0000000000..311e9b96fb
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,400 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (i int, j int);
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+CREATE TABLE mv_base_b (i int, k int);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- base table which has row level security
+DROP USER IF EXISTS ivm_admin;
+DROP USER IF EXISTS ivm_user;
+CREATE USER ivm_admin;
+CREATE USER ivm_user;
+SET SESSION AUTHORIZATION ivm_admin;
+
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four');
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+CREATE POLICY rls_tbl_policy2 ON rls_tbl FOR INSERT TO PUBLIC WITH CHECK(current_user LIKE 'ivm_%');
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+SET SESSION AUTHORIZATION ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+INSERT INTO rls_tbl VALUES
+  (3,'baz','ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER ivm_user;
+DROP USER ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.17.1


--Multipart=_Mon__2_Aug_2021_15_28_34_+0900_wlHCjIpnD/FrGAKu
Content-Type: text/x-diff;
 name="v23-0010-Add-documentations-about-Incremental-View-Mainte.patch"
Content-Disposition: attachment;
 filename="v23-0010-Add-documentations-about-Incremental-View-Mainte.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v29 10/11] Add regression tests for Incremental View Maintenance
@ 2021-03-10 02:11 Takuma Hoshiai <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Takuma Hoshiai @ 2021-03-10 02:11 UTC (permalink / raw)

---
 .../regress/expected/incremental_matview.out  | 1030 +++++++++++++++++
 src/test/regress/parallel_schedule            |    2 +-
 src/test/regress/sql/incremental_matview.sql  |  533 +++++++++
 3 files changed, 1564 insertions(+), 1 deletion(-)
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 0000000000..8946d09f5d
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1030 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (i int, j int);
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+CREATE TABLE mv_base_b (i int, k int);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS ivm_admin;
+NOTICE:  role "ivm_admin" does not exist, skipping
+DROP USER IF EXISTS ivm_user;
+NOTICE:  role "ivm_user" does not exist, skipping
+CREATE USER ivm_admin;
+CREATE USER ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by ivm_user
+SET SESSION AUTHORIZATION ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |  owner   
+----+------+----------
+  1 | foo  | ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |  owner   
+----+------+----------
+  1 | foo  | ivm_user
+  3 | baz  | ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |  owner   
+----+-------+----------
+  2 | bar   | ivm_user
+  3 | baz   | ivm_user
+  6 | corge | ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |  owner   |   num   
+----+-------+----------+---------
+  2 | bar   | ivm_user | two
+  3 | baz_2 | ivm_user | three_2
+  6 | corge | ivm_user | six
+(3 rows)
+
+-- automatic index creation
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER ivm_user;
+DROP USER ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 4df9d8503b..21f7247a07 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -78,7 +78,7 @@ test: brin_bloom brin_multi
 # psql depends on create_am
 # amutils depends on geometry, create_index_spgist, hash_index, brin
 # ----------
-test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions sysviews tsrf tid tidscan tidrangescan collate.icu.utf8 incremental_sort create_role
+test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions sysviews tsrf tid tidscan tidrangescan collate.icu.utf8 incremental_sort create_role incremental_matview
 
 # collate.*.utf8 tests cannot be run in parallel with each other
 test: rules psql psql_crosstab amutils stats_ext collate.linux.utf8 collate.windows.win1252
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 0000000000..82686f9324
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,533 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (i int, j int);
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+CREATE TABLE mv_base_b (i int, k int);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS ivm_admin;
+DROP USER IF EXISTS ivm_user;
+CREATE USER ivm_admin;
+CREATE USER ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by ivm_user
+SET SESSION AUTHORIZATION ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- automatic index creation
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER ivm_user;
+DROP USER ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.25.1


--Multipart=_Mon__28_Aug_2023_16_05_30_+0900_b1OvQD_3A3ZMTGvj
Content-Type: text/x-diff;
 name="v29-0011-Add-documentations-about-Incremental-View-Mainte.patch"
Content-Disposition: attachment;
 filename="v29-0011-Add-documentations-about-Incremental-View-Mainte.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v27 8/9] Add regression tests for Incremental View Maintenance
@ 2021-03-10 02:11 Takuma Hoshiai <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Takuma Hoshiai @ 2021-03-10 02:11 UTC (permalink / raw)

---
 .../regress/expected/incremental_matview.out  | 840 ++++++++++++++++++
 src/test/regress/parallel_schedule            |   2 +-
 src/test/regress/sql/incremental_matview.sql  | 424 +++++++++
 3 files changed, 1265 insertions(+), 1 deletion(-)
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 0000000000..201af5f087
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,840 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (i int, j int);
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+CREATE TABLE mv_base_b (i int, k int);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    13
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- base table which has row level security
+DROP USER IF EXISTS ivm_admin;
+NOTICE:  role "ivm_admin" does not exist, skipping
+DROP USER IF EXISTS ivm_user;
+NOTICE:  role "ivm_user" does not exist, skipping
+CREATE USER ivm_admin;
+CREATE USER ivm_user;
+SET SESSION AUTHORIZATION ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four');
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+CREATE POLICY rls_tbl_policy2 ON rls_tbl FOR INSERT TO PUBLIC WITH CHECK(current_user LIKE 'ivm_%');
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+SET SESSION AUTHORIZATION ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |  owner   
+----+------+----------
+  1 | foo  | ivm_user
+(1 row)
+
+INSERT INTO rls_tbl VALUES
+  (3,'baz','ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |  owner   
+----+------+----------
+  1 | foo  | ivm_user
+  3 | baz  | ivm_user
+(2 rows)
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |  owner   |   num   
+----+-------+----------+---------
+  1 | foo   | ivm_user | one
+  3 | baz_2 | ivm_user | three_2
+(2 rows)
+
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER ivm_user;
+DROP USER ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 103e11483d..3027f4e78c 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -86,7 +86,7 @@ test: brin_bloom brin_multi
 # psql depends on create_am
 # amutils depends on geometry, create_index_spgist, hash_index, brin
 # ----------
-test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions sysviews tsrf tid tidscan tidrangescan collate.icu.utf8 incremental_sort create_role
+test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions sysviews tsrf tid tidscan tidrangescan collate.icu.utf8 incremental_sort create_role incremental_matview
 
 # collate.*.utf8 tests cannot be run in parallel with each other
 test: rules psql psql_crosstab amutils stats_ext collate.linux.utf8
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 0000000000..a4ce2c741e
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,424 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (i int, j int);
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+CREATE TABLE mv_base_b (i int, k int);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- base table which has row level security
+DROP USER IF EXISTS ivm_admin;
+DROP USER IF EXISTS ivm_user;
+CREATE USER ivm_admin;
+CREATE USER ivm_user;
+SET SESSION AUTHORIZATION ivm_admin;
+
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four');
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+CREATE POLICY rls_tbl_policy2 ON rls_tbl FOR INSERT TO PUBLIC WITH CHECK(current_user LIKE 'ivm_%');
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+SET SESSION AUTHORIZATION ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+INSERT INTO rls_tbl VALUES
+  (3,'baz','ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER ivm_user;
+DROP USER ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.17.1


--Multipart=_Fri__22_Apr_2022_11_29_39_+0900_ZOAC7UMt5e8j1Nvx
Content-Type: text/x-diff;
 name="v27-0009-Add-documentations-about-Incremental-View-Mainte.patch"
Content-Disposition: attachment;
 filename="v27-0009-Add-documentations-about-Incremental-View-Mainte.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v26 09/10] Add regression tests for Incremental View Maintenance
@ 2021-03-10 02:11 Takuma Hoshiai <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Takuma Hoshiai @ 2021-03-10 02:11 UTC (permalink / raw)

---
 .../regress/expected/incremental_matview.out  | 812 ++++++++++++++++++
 src/test/regress/parallel_schedule            |   2 +-
 src/test/regress/sql/incremental_matview.sql  | 400 +++++++++
 3 files changed, 1213 insertions(+), 1 deletion(-)
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 0000000000..7b10fcddbe
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,812 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (i int, j int);
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+CREATE TABLE mv_base_b (i int, k int);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- base table which has row level security
+DROP USER IF EXISTS ivm_admin;
+NOTICE:  role "ivm_admin" does not exist, skipping
+DROP USER IF EXISTS ivm_user;
+NOTICE:  role "ivm_user" does not exist, skipping
+CREATE USER ivm_admin;
+CREATE USER ivm_user;
+SET SESSION AUTHORIZATION ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four');
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+CREATE POLICY rls_tbl_policy2 ON rls_tbl FOR INSERT TO PUBLIC WITH CHECK(current_user LIKE 'ivm_%');
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+SET SESSION AUTHORIZATION ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |  owner   
+----+------+----------
+  1 | foo  | ivm_user
+(1 row)
+
+INSERT INTO rls_tbl VALUES
+  (3,'baz','ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |  owner   
+----+------+----------
+  1 | foo  | ivm_user
+  3 | baz  | ivm_user
+(2 rows)
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |  owner   |   num   
+----+-------+----------+---------
+  1 | foo   | ivm_user | one
+  3 | baz_2 | ivm_user | three_2
+(2 rows)
+
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER ivm_user;
+DROP USER ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 6d8f524ae9..79988e068c 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -86,7 +86,7 @@ test: brin_bloom brin_multi
 # psql depends on create_am
 # amutils depends on geometry, create_index_spgist, hash_index, brin
 # ----------
-test: create_table_like alter_generic alter_operator misc async dbsize misc_functions sysviews tsrf tid tidscan tidrangescan collate.icu.utf8 incremental_sort create_role
+test: create_table_like alter_generic alter_operator misc async dbsize misc_functions sysviews tsrf tid tidscan tidrangescan collate.icu.utf8 incremental_sort create_role incremental_matview
 
 # collate.*.utf8 tests cannot be run in parallel with each other
 test: rules psql psql_crosstab amutils stats_ext collate.linux.utf8
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 0000000000..311e9b96fb
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,400 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (i int, j int);
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+CREATE TABLE mv_base_b (i int, k int);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- base table which has row level security
+DROP USER IF EXISTS ivm_admin;
+DROP USER IF EXISTS ivm_user;
+CREATE USER ivm_admin;
+CREATE USER ivm_user;
+SET SESSION AUTHORIZATION ivm_admin;
+
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four');
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+CREATE POLICY rls_tbl_policy2 ON rls_tbl FOR INSERT TO PUBLIC WITH CHECK(current_user LIKE 'ivm_%');
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+SET SESSION AUTHORIZATION ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+INSERT INTO rls_tbl VALUES
+  (3,'baz','ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER ivm_user;
+DROP USER ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.17.1


--Multipart=_Mon__14_Mar_2022_19_12_17_+0900_E9HVp8j5QFkIIek.
Content-Type: text/x-diff;
 name="v26-0008-Add-aggregates-support-in-IVM.patch"
Content-Disposition: attachment;
 filename="v26-0008-Add-aggregates-support-in-IVM.patch"
Content-Transfer-Encoding: quoted-printable



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v24 09/15] Add regression tests for Incremental View Maintenance
@ 2021-03-10 02:11 Takuma Hoshiai <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Takuma Hoshiai @ 2021-03-10 02:11 UTC (permalink / raw)

---
 .../regress/expected/incremental_matview.out  | 812 ++++++++++++++++++
 src/test/regress/parallel_schedule            |   2 +-
 src/test/regress/sql/incremental_matview.sql  | 400 +++++++++
 3 files changed, 1213 insertions(+), 1 deletion(-)
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 0000000000..4b14100acd
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,812 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (i int, j int);
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+CREATE TABLE mv_base_b (i int, k int);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- base table which has row level security
+DROP USER IF EXISTS ivm_admin;
+NOTICE:  role "ivm_admin" does not exist, skipping
+DROP USER IF EXISTS ivm_user;
+NOTICE:  role "ivm_user" does not exist, skipping
+CREATE USER ivm_admin;
+CREATE USER ivm_user;
+SET SESSION AUTHORIZATION ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four');
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+CREATE POLICY rls_tbl_policy2 ON rls_tbl FOR INSERT TO PUBLIC WITH CHECK(current_user LIKE 'ivm_%');
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+SET SESSION AUTHORIZATION ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |  owner   
+----+------+----------
+  1 | foo  | ivm_user
+(1 row)
+
+INSERT INTO rls_tbl VALUES
+  (3,'baz','ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |  owner   
+----+------+----------
+  1 | foo  | ivm_user
+  3 | baz  | ivm_user
+(2 rows)
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |  owner   |   num   
+----+-------+----------+---------
+  1 | foo   | ivm_user | one
+  3 | baz_2 | ivm_user | three_2
+(2 rows)
+
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER ivm_user;
+DROP USER ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 7be89178f0..b0350f47dd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -86,7 +86,7 @@ test: brin_bloom brin_multi
 # ----------
 # Another group of parallel tests
 # ----------
-test: create_table_like alter_generic alter_operator misc async dbsize misc_functions sysviews tsrf tid tidscan tidrangescan collate.icu.utf8 incremental_sort
+test: create_table_like alter_generic alter_operator misc async dbsize misc_functions sysviews tsrf tid tidscan tidrangescan collate.icu.utf8 incremental_sort incremental_matview
 
 # rules cannot run concurrently with any test that creates
 # a view or rule in the public schema
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 0000000000..311e9b96fb
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,400 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (i int, j int);
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+CREATE TABLE mv_base_b (i int, k int);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- base table which has row level security
+DROP USER IF EXISTS ivm_admin;
+DROP USER IF EXISTS ivm_user;
+CREATE USER ivm_admin;
+CREATE USER ivm_user;
+SET SESSION AUTHORIZATION ivm_admin;
+
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four');
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+CREATE POLICY rls_tbl_policy2 ON rls_tbl FOR INSERT TO PUBLIC WITH CHECK(current_user LIKE 'ivm_%');
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+SET SESSION AUTHORIZATION ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+INSERT INTO rls_tbl VALUES
+  (3,'baz','ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER ivm_user;
+DROP USER ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.17.1


--Multipart=_Fri__29_Oct_2021_18_16_28_+0900_jlYRKjywLqhZ7oyk
Content-Type: text/x-diff;
 name="v24-0010-Add-documentations-about-Incremental-View-Mainte.patch"
Content-Disposition: attachment;
 filename="v24-0010-Add-documentations-about-Incremental-View-Mainte.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v34 10/11] Add regression tests for Incremental View Maintenance
@ 2021-03-10 02:11 Takuma Hoshiai <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Takuma Hoshiai @ 2021-03-10 02:11 UTC (permalink / raw)

---
 .../regress/expected/incremental_matview.out  | 1030 +++++++++++++++++
 src/test/regress/parallel_schedule            |    2 +-
 src/test/regress/sql/incremental_matview.sql  |  533 +++++++++
 3 files changed, 1564 insertions(+), 1 deletion(-)
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 0000000000..d65896425e
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1030 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (i int, j int);
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+CREATE TABLE mv_base_b (i int, k int);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- automatic index creation
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 2429ec2bba..03814f34e9 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -78,7 +78,7 @@ test: brin_bloom brin_multi
 # psql depends on create_am
 # amutils depends on geometry, create_index_spgist, hash_index, brin
 # ----------
-test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role
+test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 test: rules psql psql_crosstab amutils stats_ext collate.linux.utf8 collate.windows.win1252
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 0000000000..90116edff8
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,533 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (i int, j int);
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+CREATE TABLE mv_base_b (i int, k int);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- automatic index creation
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.34.1


--Multipart=_Thu__11_Jul_2024_13_23_57_+0900_hKsU2G3a3BgS2FFs
Content-Type: text/x-diff;
 name="v34-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v34-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v25 09/15] Add regression tests for Incremental View Maintenance
@ 2021-03-10 02:11 Takuma Hoshiai <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Takuma Hoshiai @ 2021-03-10 02:11 UTC (permalink / raw)

---
 .../regress/expected/incremental_matview.out  | 812 ++++++++++++++++++
 src/test/regress/parallel_schedule            |   2 +-
 src/test/regress/sql/incremental_matview.sql  | 400 +++++++++
 3 files changed, 1213 insertions(+), 1 deletion(-)
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 0000000000..7b10fcddbe
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,812 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (i int, j int);
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+CREATE TABLE mv_base_b (i int, k int);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- base table which has row level security
+DROP USER IF EXISTS ivm_admin;
+NOTICE:  role "ivm_admin" does not exist, skipping
+DROP USER IF EXISTS ivm_user;
+NOTICE:  role "ivm_user" does not exist, skipping
+CREATE USER ivm_admin;
+CREATE USER ivm_user;
+SET SESSION AUTHORIZATION ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four');
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+CREATE POLICY rls_tbl_policy2 ON rls_tbl FOR INSERT TO PUBLIC WITH CHECK(current_user LIKE 'ivm_%');
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+SET SESSION AUTHORIZATION ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |  owner   
+----+------+----------
+  1 | foo  | ivm_user
+(1 row)
+
+INSERT INTO rls_tbl VALUES
+  (3,'baz','ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |  owner   
+----+------+----------
+  1 | foo  | ivm_user
+  3 | baz  | ivm_user
+(2 rows)
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |  owner   |   num   
+----+-------+----------+---------
+  1 | foo   | ivm_user | one
+  3 | baz_2 | ivm_user | three_2
+(2 rows)
+
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER ivm_user;
+DROP USER ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 861c30a73a..a838d176dd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -89,7 +89,7 @@ test: brin_bloom brin_multi
 # ----------
 # Another group of parallel tests
 # ----------
-test: create_table_like alter_generic alter_operator misc async dbsize misc_functions sysviews tsrf tid tidscan tidrangescan collate.icu.utf8 incremental_sort create_role
+test: create_table_like alter_generic alter_operator misc async dbsize misc_functions sysviews tsrf tid tidscan tidrangescan collate.icu.utf8 incremental_sort create_role incremental_matview
 
 # rules cannot run concurrently with any test that creates
 # a view or rule in the public schema
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 0000000000..311e9b96fb
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,400 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (i int, j int);
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+CREATE TABLE mv_base_b (i int, k int);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- base table which has row level security
+DROP USER IF EXISTS ivm_admin;
+DROP USER IF EXISTS ivm_user;
+CREATE USER ivm_admin;
+CREATE USER ivm_user;
+SET SESSION AUTHORIZATION ivm_admin;
+
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four');
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+CREATE POLICY rls_tbl_policy2 ON rls_tbl FOR INSERT TO PUBLIC WITH CHECK(current_user LIKE 'ivm_%');
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+SET SESSION AUTHORIZATION ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+INSERT INTO rls_tbl VALUES
+  (3,'baz','ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER ivm_user;
+DROP USER ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.17.1


--Multipart=_Fri__4_Feb_2022_01_48_06_+0900_N8BNZpfOR27sWrgY
Content-Type: text/x-diff;
 name="v25-0008-Add-aggregates-support-in-IVM.patch"
Content-Disposition: attachment;
 filename="v25-0008-Add-aggregates-support-in-IVM.patch"
Content-Transfer-Encoding: quoted-printable



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v32 10/11] Add regression tests for Incremental View Maintenance
@ 2021-03-10 02:11 Takuma Hoshiai <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Takuma Hoshiai @ 2021-03-10 02:11 UTC (permalink / raw)

---
 .../regress/expected/incremental_matview.out  | 1030 +++++++++++++++++
 src/test/regress/parallel_schedule            |    2 +-
 src/test/regress/sql/incremental_matview.sql  |  533 +++++++++
 3 files changed, 1564 insertions(+), 1 deletion(-)
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 0000000000..d65896425e
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1030 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (i int, j int);
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+CREATE TABLE mv_base_b (i int, k int);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- automatic index creation
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 5ac6e871f5..64c910af65 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -78,7 +78,7 @@ test: brin_bloom brin_multi
 # psql depends on create_am
 # amutils depends on geometry, create_index_spgist, hash_index, brin
 # ----------
-test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps
+test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 test: rules psql psql_crosstab amutils stats_ext collate.linux.utf8 collate.windows.win1252
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 0000000000..90116edff8
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,533 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (i int, j int);
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+CREATE TABLE mv_base_b (i int, k int);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- automatic index creation
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.25.1


--Multipart=_Sun__31_Mar_2024_22_59_31_+0900_msknEviJj08_wgqO
Content-Type: text/x-diff;
 name="v32-0011-Add-documentations-about-Incremental-View-Mainte.patch"
Content-Disposition: attachment;
 filename="v32-0011-Add-documentations-about-Incremental-View-Mainte.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v33 10/11] Add regression tests for Incremental View Maintenance
@ 2021-03-10 02:11 Takuma Hoshiai <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Takuma Hoshiai @ 2021-03-10 02:11 UTC (permalink / raw)

---
 .../regress/expected/incremental_matview.out  | 1030 +++++++++++++++++
 src/test/regress/parallel_schedule            |    2 +-
 src/test/regress/sql/incremental_matview.sql  |  533 +++++++++
 3 files changed, 1564 insertions(+), 1 deletion(-)
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 0000000000..d65896425e
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1030 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (i int, j int);
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+CREATE TABLE mv_base_b (i int, k int);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- automatic index creation
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 2429ec2bba..03814f34e9 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -78,7 +78,7 @@ test: brin_bloom brin_multi
 # psql depends on create_am
 # amutils depends on geometry, create_index_spgist, hash_index, brin
 # ----------
-test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role
+test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 test: rules psql psql_crosstab amutils stats_ext collate.linux.utf8 collate.windows.win1252
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 0000000000..90116edff8
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,533 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (i int, j int);
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+CREATE TABLE mv_base_b (i int, k int);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- automatic index creation
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.25.1


--Multipart=_Tue__2_Jul_2024_17_03_11_+0900_6OrVBZxOB4o_k6A1
Content-Type: text/x-diff;
 name="v33-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v33-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v24 09/15] Add regression tests for Incremental View Maintenance
@ 2021-03-10 02:11 Takuma Hoshiai <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Takuma Hoshiai @ 2021-03-10 02:11 UTC (permalink / raw)

---
 .../regress/expected/incremental_matview.out  | 812 ++++++++++++++++++
 src/test/regress/parallel_schedule            |   2 +-
 src/test/regress/sql/incremental_matview.sql  | 400 +++++++++
 3 files changed, 1213 insertions(+), 1 deletion(-)
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 0000000000..4b14100acd
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,812 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (i int, j int);
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+CREATE TABLE mv_base_b (i int, k int);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- base table which has row level security
+DROP USER IF EXISTS ivm_admin;
+NOTICE:  role "ivm_admin" does not exist, skipping
+DROP USER IF EXISTS ivm_user;
+NOTICE:  role "ivm_user" does not exist, skipping
+CREATE USER ivm_admin;
+CREATE USER ivm_user;
+SET SESSION AUTHORIZATION ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four');
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+CREATE POLICY rls_tbl_policy2 ON rls_tbl FOR INSERT TO PUBLIC WITH CHECK(current_user LIKE 'ivm_%');
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+SET SESSION AUTHORIZATION ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |  owner   
+----+------+----------
+  1 | foo  | ivm_user
+(1 row)
+
+INSERT INTO rls_tbl VALUES
+  (3,'baz','ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |  owner   
+----+------+----------
+  1 | foo  | ivm_user
+  3 | baz  | ivm_user
+(2 rows)
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |  owner   |   num   
+----+-------+----------+---------
+  1 | foo   | ivm_user | one
+  3 | baz_2 | ivm_user | three_2
+(2 rows)
+
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER ivm_user;
+DROP USER ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 7be89178f0..b0350f47dd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -86,7 +86,7 @@ test: brin_bloom brin_multi
 # ----------
 # Another group of parallel tests
 # ----------
-test: create_table_like alter_generic alter_operator misc async dbsize misc_functions sysviews tsrf tid tidscan tidrangescan collate.icu.utf8 incremental_sort
+test: create_table_like alter_generic alter_operator misc async dbsize misc_functions sysviews tsrf tid tidscan tidrangescan collate.icu.utf8 incremental_sort incremental_matview
 
 # rules cannot run concurrently with any test that creates
 # a view or rule in the public schema
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 0000000000..311e9b96fb
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,400 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (i int, j int);
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+CREATE TABLE mv_base_b (i int, k int);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- base table which has row level security
+DROP USER IF EXISTS ivm_admin;
+DROP USER IF EXISTS ivm_user;
+CREATE USER ivm_admin;
+CREATE USER ivm_user;
+SET SESSION AUTHORIZATION ivm_admin;
+
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four');
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+CREATE POLICY rls_tbl_policy2 ON rls_tbl FOR INSERT TO PUBLIC WITH CHECK(current_user LIKE 'ivm_%');
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+SET SESSION AUTHORIZATION ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+INSERT INTO rls_tbl VALUES
+  (3,'baz','ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER ivm_user;
+DROP USER ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.17.1


--Multipart=_Thu__23_Sep_2021_04_57_30_+0900_b5pmgR1N8oMaMz.U
Content-Type: text/x-diff;
 name="v24-0010-Add-documentations-about-Incremental-View-Mainte.patch"
Content-Disposition: attachment;
 filename="v24-0010-Add-documentations-about-Incremental-View-Mainte.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v30 10/11] Add regression tests for Incremental View Maintenance
@ 2021-03-10 02:11 Takuma Hoshiai <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Takuma Hoshiai @ 2021-03-10 02:11 UTC (permalink / raw)

---
 .../regress/expected/incremental_matview.out  | 1030 +++++++++++++++++
 src/test/regress/parallel_schedule            |    2 +-
 src/test/regress/sql/incremental_matview.sql  |  533 +++++++++
 3 files changed, 1564 insertions(+), 1 deletion(-)
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 0000000000..8946d09f5d
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1030 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (i int, j int);
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+CREATE TABLE mv_base_b (i int, k int);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS ivm_admin;
+NOTICE:  role "ivm_admin" does not exist, skipping
+DROP USER IF EXISTS ivm_user;
+NOTICE:  role "ivm_user" does not exist, skipping
+CREATE USER ivm_admin;
+CREATE USER ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by ivm_user
+SET SESSION AUTHORIZATION ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |  owner   
+----+------+----------
+  1 | foo  | ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |  owner   
+----+------+----------
+  1 | foo  | ivm_user
+  3 | baz  | ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |  owner   
+----+-------+----------
+  2 | bar   | ivm_user
+  3 | baz   | ivm_user
+  6 | corge | ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |  owner   |   num   
+----+-------+----------+---------
+  2 | bar   | ivm_user | two
+  3 | baz_2 | ivm_user | three_2
+  6 | corge | ivm_user | six
+(3 rows)
+
+-- automatic index creation
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER ivm_user;
+DROP USER ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 1d8a414eea..84c3c5e9be 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -78,7 +78,7 @@ test: brin_bloom brin_multi
 # psql depends on create_am
 # amutils depends on geometry, create_index_spgist, hash_index, brin
 # ----------
-test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions sysviews tsrf tid tidscan tidrangescan collate.icu.utf8 incremental_sort create_role without_overlaps
+test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions sysviews tsrf tid tidscan tidrangescan collate.icu.utf8 incremental_sort create_role without_overlaps incremental_matview
 
 # collate.*.utf8 tests cannot be run in parallel with each other
 test: rules psql psql_crosstab amutils stats_ext collate.linux.utf8 collate.windows.win1252
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 0000000000..82686f9324
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,533 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (i int, j int);
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+CREATE TABLE mv_base_b (i int, k int);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS ivm_admin;
+DROP USER IF EXISTS ivm_user;
+CREATE USER ivm_admin;
+CREATE USER ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by ivm_user
+SET SESSION AUTHORIZATION ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- automatic index creation
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER ivm_user;
+DROP USER ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.25.1


--Multipart=_Mon__4_Mar_2024_11_58_46_+0900_UaponF/qQhQrVCFt
Content-Type: text/x-diff;
 name="v30-0011-Add-documentations-about-Incremental-View-Mainte.patch"
Content-Disposition: attachment;
 filename="v30-0011-Add-documentations-about-Incremental-View-Mainte.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v27 8/9] Add regression tests for Incremental View Maintenance
@ 2021-03-10 02:11 Takuma Hoshiai <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Takuma Hoshiai @ 2021-03-10 02:11 UTC (permalink / raw)

---
 .../regress/expected/incremental_matview.out  | 840 ++++++++++++++++++
 src/test/regress/parallel_schedule            |   2 +-
 src/test/regress/sql/incremental_matview.sql  | 424 +++++++++
 3 files changed, 1265 insertions(+), 1 deletion(-)
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 0000000000..201af5f087
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,840 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (i int, j int);
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+CREATE TABLE mv_base_b (i int, k int);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    13
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- base table which has row level security
+DROP USER IF EXISTS ivm_admin;
+NOTICE:  role "ivm_admin" does not exist, skipping
+DROP USER IF EXISTS ivm_user;
+NOTICE:  role "ivm_user" does not exist, skipping
+CREATE USER ivm_admin;
+CREATE USER ivm_user;
+SET SESSION AUTHORIZATION ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four');
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+CREATE POLICY rls_tbl_policy2 ON rls_tbl FOR INSERT TO PUBLIC WITH CHECK(current_user LIKE 'ivm_%');
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+SET SESSION AUTHORIZATION ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |  owner   
+----+------+----------
+  1 | foo  | ivm_user
+(1 row)
+
+INSERT INTO rls_tbl VALUES
+  (3,'baz','ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |  owner   
+----+------+----------
+  1 | foo  | ivm_user
+  3 | baz  | ivm_user
+(2 rows)
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |  owner   |   num   
+----+-------+----------+---------
+  1 | foo   | ivm_user | one
+  3 | baz_2 | ivm_user | three_2
+(2 rows)
+
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER ivm_user;
+DROP USER ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 103e11483d..3027f4e78c 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -86,7 +86,7 @@ test: brin_bloom brin_multi
 # psql depends on create_am
 # amutils depends on geometry, create_index_spgist, hash_index, brin
 # ----------
-test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions sysviews tsrf tid tidscan tidrangescan collate.icu.utf8 incremental_sort create_role
+test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions sysviews tsrf tid tidscan tidrangescan collate.icu.utf8 incremental_sort create_role incremental_matview
 
 # collate.*.utf8 tests cannot be run in parallel with each other
 test: rules psql psql_crosstab amutils stats_ext collate.linux.utf8
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 0000000000..a4ce2c741e
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,424 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (i int, j int);
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+CREATE TABLE mv_base_b (i int, k int);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- base table which has row level security
+DROP USER IF EXISTS ivm_admin;
+DROP USER IF EXISTS ivm_user;
+CREATE USER ivm_admin;
+CREATE USER ivm_user;
+SET SESSION AUTHORIZATION ivm_admin;
+
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four');
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+CREATE POLICY rls_tbl_policy2 ON rls_tbl FOR INSERT TO PUBLIC WITH CHECK(current_user LIKE 'ivm_%');
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+SET SESSION AUTHORIZATION ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+INSERT INTO rls_tbl VALUES
+  (3,'baz','ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER ivm_user;
+DROP USER ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.17.1


--Multipart=_Fri__22_Apr_2022_14_58_01_+0900_MN3L/o2YUVF2g4zw
Content-Type: text/x-diff;
 name="v27-0009-Add-documentations-about-Incremental-View-Mainte.patch"
Content-Disposition: attachment;
 filename="v27-0009-Add-documentations-about-Incremental-View-Mainte.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v29 10/11] Add regression tests for Incremental View Maintenance
@ 2021-03-10 02:11 Takuma Hoshiai <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Takuma Hoshiai @ 2021-03-10 02:11 UTC (permalink / raw)

---
 src/bin/pg_dump/pg_dump.h                     |    1 +
 .../regress/expected/incremental_matview.out  | 1030 +++++++++++++++++
 src/test/regress/parallel_schedule            |    2 +-
 src/test/regress/sql/incremental_matview.sql  |  533 +++++++++
 4 files changed, 1565 insertions(+), 1 deletion(-)
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index 3705891d25..71ea246abd 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -323,6 +323,7 @@ typedef struct _tableInfo
 
 	int			numParents;		/* number of (immediate) parent tables */
 	struct _tableInfo **parents;	/* TableInfos of immediate parents */
+
 	bool		isivm;			/* is incrementally maintainable materialized view? */
 
 	/*
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 0000000000..8946d09f5d
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1030 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (i int, j int);
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+CREATE TABLE mv_base_b (i int, k int);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS ivm_admin;
+NOTICE:  role "ivm_admin" does not exist, skipping
+DROP USER IF EXISTS ivm_user;
+NOTICE:  role "ivm_user" does not exist, skipping
+CREATE USER ivm_admin;
+CREATE USER ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by ivm_user
+SET SESSION AUTHORIZATION ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |  owner   
+----+------+----------
+  1 | foo  | ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |  owner   
+----+------+----------
+  1 | foo  | ivm_user
+  3 | baz  | ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |  owner   
+----+-------+----------
+  2 | bar   | ivm_user
+  3 | baz   | ivm_user
+  6 | corge | ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |  owner   |   num   
+----+-------+----------+---------
+  2 | bar   | ivm_user | two
+  3 | baz_2 | ivm_user | three_2
+  6 | corge | ivm_user | six
+(3 rows)
+
+-- automatic index creation
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER ivm_user;
+DROP USER ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 4df9d8503b..21f7247a07 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -78,7 +78,7 @@ test: brin_bloom brin_multi
 # psql depends on create_am
 # amutils depends on geometry, create_index_spgist, hash_index, brin
 # ----------
-test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions sysviews tsrf tid tidscan tidrangescan collate.icu.utf8 incremental_sort create_role
+test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions sysviews tsrf tid tidscan tidrangescan collate.icu.utf8 incremental_sort create_role incremental_matview
 
 # collate.*.utf8 tests cannot be run in parallel with each other
 test: rules psql psql_crosstab amutils stats_ext collate.linux.utf8 collate.windows.win1252
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 0000000000..82686f9324
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,533 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (i int, j int);
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+CREATE TABLE mv_base_b (i int, k int);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS ivm_admin;
+DROP USER IF EXISTS ivm_user;
+CREATE USER ivm_admin;
+CREATE USER ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by ivm_user
+SET SESSION AUTHORIZATION ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- automatic index creation
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER ivm_user;
+DROP USER ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.25.1


--Multipart=_Mon__28_Aug_2023_11_52_52_+0900_hj6L5h176QaSGtg7
Content-Type: text/x-diff;
 name="v29-0011-Add-documentations-about-Incremental-View-Mainte.patch"
Content-Disposition: attachment;
 filename="v29-0011-Add-documentations-about-Incremental-View-Mainte.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v7 4/7] Row pattern recognition patch (executor).
@ 2023-09-22 04:53 Tatsuo Ishii <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Tatsuo Ishii @ 2023-09-22 04:53 UTC (permalink / raw)

---
 src/backend/executor/nodeWindowAgg.c | 853 ++++++++++++++++++++++++++-
 src/backend/utils/adt/windowfuncs.c  |  37 +-
 src/include/catalog/pg_proc.dat      |   6 +
 src/include/nodes/execnodes.h        |  26 +
 4 files changed, 909 insertions(+), 13 deletions(-)

diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c
index 310ac23e3a..84d1b8acaa 100644
--- a/src/backend/executor/nodeWindowAgg.c
+++ b/src/backend/executor/nodeWindowAgg.c
@@ -36,6 +36,7 @@
 #include "access/htup_details.h"
 #include "catalog/objectaccess.h"
 #include "catalog/pg_aggregate.h"
+#include "catalog/pg_collation_d.h"
 #include "catalog/pg_proc.h"
 #include "executor/executor.h"
 #include "executor/nodeWindowAgg.h"
@@ -48,6 +49,7 @@
 #include "utils/acl.h"
 #include "utils/builtins.h"
 #include "utils/datum.h"
+#include "utils/fmgroids.h"
 #include "utils/expandeddatum.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
@@ -182,8 +184,9 @@ static void begin_partition(WindowAggState *winstate);
 static void spool_tuples(WindowAggState *winstate, int64 pos);
 static void release_partition(WindowAggState *winstate);
 
-static int	row_is_in_frame(WindowAggState *winstate, int64 pos,
+static int  row_is_in_frame(WindowAggState *winstate, int64 pos,
 							TupleTableSlot *slot);
+
 static void update_frameheadpos(WindowAggState *winstate);
 static void update_frametailpos(WindowAggState *winstate);
 static void update_grouptailpos(WindowAggState *winstate);
@@ -195,9 +198,32 @@ static Datum GetAggInitVal(Datum textInitVal, Oid transtype);
 
 static bool are_peers(WindowAggState *winstate, TupleTableSlot *slot1,
 					  TupleTableSlot *slot2);
-static bool window_gettupleslot(WindowObject winobj, int64 pos,
-								TupleTableSlot *slot);
 
+static int	WinGetSlotInFrame(WindowObject winobj, TupleTableSlot *slot,
+							  int relpos, int seektype, bool set_mark,
+							  bool *isnull, bool *isout);
+static bool window_gettupleslot(WindowObject winobj, int64 pos, TupleTableSlot *slot);
+
+static void attno_map(Node *node);
+static bool attno_map_walker(Node *node, void *context);
+static int	row_is_in_reduced_frame(WindowObject winobj, int64 pos);
+static bool rpr_is_defined(WindowAggState *winstate);
+
+static void create_reduced_frame_map(WindowAggState *winstate);
+static int	get_reduced_frame_map(WindowAggState *winstate, int64 pos);
+static void register_reduced_frame_map(WindowAggState *winstate, int64 pos, int val);
+static void clear_reduced_frame_map(WindowAggState *winstate);
+static void update_reduced_frame(WindowObject winobj, int64 pos);
+
+static int64 evaluate_pattern(WindowObject winobj, int64 current_pos,
+							  char *vname, StringInfo encoded_str, bool *result);
+
+static bool get_slots(WindowObject winobj, int64 current_pos);
+
+static int	search_str_set(char *pattern, StringInfo *str_set, int set_size);
+static void search_str_set_recurse(char *pattern, StringInfo *str_set, int set_size, int set_index,
+								   int str_index, char *encoded_str, int *resultlen);
+static char	pattern_initial(WindowAggState *winstate, char *vname);
 
 /*
  * initialize_windowaggregate
@@ -673,6 +699,7 @@ eval_windowaggregates(WindowAggState *winstate)
 	WindowObject agg_winobj;
 	TupleTableSlot *agg_row_slot;
 	TupleTableSlot *temp_slot;
+	bool		agg_result_isnull;
 
 	numaggs = winstate->numaggs;
 	if (numaggs == 0)
@@ -778,6 +805,9 @@ eval_windowaggregates(WindowAggState *winstate)
 	 * Note that we don't strictly need to restart in the last case, but if
 	 * we're going to remove all rows from the aggregation anyway, a restart
 	 * surely is faster.
+	 *
+	 *   - if RPR is enabled and skip mode is SKIP TO NEXT ROW,
+	 *     we restart aggregation too.
 	 *----------
 	 */
 	numaggs_restart = 0;
@@ -788,8 +818,11 @@ eval_windowaggregates(WindowAggState *winstate)
 			(winstate->aggregatedbase != winstate->frameheadpos &&
 			 !OidIsValid(peraggstate->invtransfn_oid)) ||
 			(winstate->frameOptions & FRAMEOPTION_EXCLUSION) ||
-			winstate->aggregatedupto <= winstate->frameheadpos)
+			winstate->aggregatedupto <= winstate->frameheadpos ||
+			(rpr_is_defined(winstate) &&
+			 winstate->rpSkipTo == ST_NEXT_ROW))
 		{
+			elog(DEBUG1, "peraggstate->restart is set");
 			peraggstate->restart = true;
 			numaggs_restart++;
 		}
@@ -861,8 +894,10 @@ eval_windowaggregates(WindowAggState *winstate)
 	 * If we created a mark pointer for aggregates, keep it pushed up to frame
 	 * head, so that tuplestore can discard unnecessary rows.
 	 */
+#ifdef NOT_USED
 	if (agg_winobj->markptr >= 0)
 		WinSetMarkPosition(agg_winobj, winstate->frameheadpos);
+#endif
 
 	/*
 	 * Now restart the aggregates that require it.
@@ -917,6 +952,29 @@ eval_windowaggregates(WindowAggState *winstate)
 	{
 		winstate->aggregatedupto = winstate->frameheadpos;
 		ExecClearTuple(agg_row_slot);
+
+		/*
+		 * If RPR is defined, we do not use aggregatedupto_nonrestarted.  To
+		 * avoid assertion failure below, we reset aggregatedupto_nonrestarted
+		 * to frameheadpos.
+		 */
+		if (rpr_is_defined(winstate))
+			aggregatedupto_nonrestarted = winstate->frameheadpos;
+	}
+
+	agg_result_isnull = false;
+	/* RPR is defined? */
+	if (rpr_is_defined(winstate))
+	{
+		/*
+		 * If the skip mode is SKIP TO PAST LAST ROW and we already know that
+		 * current row is a skipped row, we don't need to accumulate rows,
+		 * just return NULL. Note that for unamtched row, we need to do
+		 * aggregation so that count(*) shows 0, rather than NULL.
+		 */
+		if (winstate->rpSkipTo == ST_PAST_LAST_ROW &&
+			get_reduced_frame_map(winstate, winstate->currentpos) == RF_SKIPPED)
+			agg_result_isnull = true;
 	}
 
 	/*
@@ -930,6 +988,11 @@ eval_windowaggregates(WindowAggState *winstate)
 	{
 		int			ret;
 
+		elog(DEBUG1, "===== loop in frame starts: " INT64_FORMAT, winstate->aggregatedupto);
+
+		if (agg_result_isnull)
+			break;
+
 		/* Fetch next row if we didn't already */
 		if (TupIsNull(agg_row_slot))
 		{
@@ -945,9 +1008,28 @@ eval_windowaggregates(WindowAggState *winstate)
 		ret = row_is_in_frame(winstate, winstate->aggregatedupto, agg_row_slot);
 		if (ret < 0)
 			break;
+
 		if (ret == 0)
 			goto next_tuple;
 
+		if (rpr_is_defined(winstate))
+		{
+			/*
+			 * If the row status at currentpos is already decided and current
+			 * row status is not decided yet, it means we passed the last
+			 * reduced frame. Time to break the loop.
+			 */
+			if (get_reduced_frame_map(winstate, winstate->currentpos) != RF_NOT_DETERMINED &&
+				get_reduced_frame_map(winstate, winstate->aggregatedupto) == RF_NOT_DETERMINED)
+				break;
+			/*
+			 * Otherwise we need to calculate the reduced frame.
+			 */
+			ret = row_is_in_reduced_frame(winstate->agg_winobj, winstate->aggregatedupto);
+			if (ret == -1)	/* unmatched row */
+				break;
+		}
+
 		/* Set tuple context for evaluation of aggregate arguments */
 		winstate->tmpcontext->ecxt_outertuple = agg_row_slot;
 
@@ -976,6 +1058,7 @@ next_tuple:
 		ExecClearTuple(agg_row_slot);
 	}
 
+
 	/* The frame's end is not supposed to move backwards, ever */
 	Assert(aggregatedupto_nonrestarted <= winstate->aggregatedupto);
 
@@ -996,6 +1079,16 @@ next_tuple:
 								 peraggstate,
 								 result, isnull);
 
+		/*
+		 * RPR is defined and we just return NULL because skip mode is SKIP
+		 * TO PAST LAST ROW and current row is skipped row.
+		 */
+		if (agg_result_isnull)
+		{
+			*isnull = true;
+			*result = (Datum) 0;
+		}
+
 		/*
 		 * save the result in case next row shares the same frame.
 		 *
@@ -1090,6 +1183,7 @@ begin_partition(WindowAggState *winstate)
 	winstate->framehead_valid = false;
 	winstate->frametail_valid = false;
 	winstate->grouptail_valid = false;
+	create_reduced_frame_map(winstate);
 	winstate->spooled_rows = 0;
 	winstate->currentpos = 0;
 	winstate->frameheadpos = 0;
@@ -2053,6 +2147,8 @@ ExecWindowAgg(PlanState *pstate)
 
 	CHECK_FOR_INTERRUPTS();
 
+	elog(DEBUG1, "ExecWindowAgg called. pos: " INT64_FORMAT , winstate->currentpos);
+
 	if (winstate->status == WINDOWAGG_DONE)
 		return NULL;
 
@@ -2221,6 +2317,17 @@ ExecWindowAgg(PlanState *pstate)
 		/* don't evaluate the window functions when we're in pass-through mode */
 		if (winstate->status == WINDOWAGG_RUN)
 		{
+			/*
+			 * If RPR is defined and skip mode is next row, we need to clear existing
+			 * reduced frame info so that we newly calculate the info starting from
+			 * current row.
+			 */
+			if (rpr_is_defined(winstate))
+			{
+				if (winstate->rpSkipTo == ST_NEXT_ROW)
+					clear_reduced_frame_map(winstate);
+			}
+
 			/*
 			 * Evaluate true window functions
 			 */
@@ -2388,6 +2495,9 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags)
 	TupleDesc	scanDesc;
 	ListCell   *l;
 
+	TargetEntry	*te;
+	Expr		*expr;
+
 	/* check for unsupported flags */
 	Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
 
@@ -2483,6 +2593,16 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags)
 	winstate->temp_slot_2 = ExecInitExtraTupleSlot(estate, scanDesc,
 												   &TTSOpsMinimalTuple);
 
+	winstate->prev_slot = ExecInitExtraTupleSlot(estate, scanDesc,
+												 &TTSOpsMinimalTuple);
+
+	winstate->next_slot = ExecInitExtraTupleSlot(estate, scanDesc,
+												 &TTSOpsMinimalTuple);
+
+	winstate->null_slot = ExecInitExtraTupleSlot(estate, scanDesc,
+												 &TTSOpsMinimalTuple);
+	winstate->null_slot = ExecStoreAllNullTuple(winstate->null_slot);
+
 	/*
 	 * create frame head and tail slots only if needed (must create slots in
 	 * exactly the same cases that update_frameheadpos and update_frametailpos
@@ -2667,6 +2787,39 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags)
 	winstate->inRangeAsc = node->inRangeAsc;
 	winstate->inRangeNullsFirst = node->inRangeNullsFirst;
 
+	/* Set up SKIP TO type */
+	winstate->rpSkipTo = node->rpSkipTo;
+	/* Set up row pattern recognition PATTERN clause */
+	winstate->patternVariableList = node->patternVariable;
+	winstate->patternRegexpList = node->patternRegexp;
+
+	/* Set up row pattern recognition DEFINE clause */
+	winstate->defineInitial = node->defineInitial;
+	winstate->defineVariableList = NIL;
+	winstate->defineClauseList = NIL;
+	if (node->defineClause != NIL)
+	{
+		/*
+		 * Tweak arg var of PREV/NEXT so that it refers to scan/inner slot.
+		 */
+		foreach(l, node->defineClause)
+		{
+			char		*name;
+			ExprState	*exps;
+
+			te = lfirst(l);
+			name = te->resname;
+			expr = te->expr;
+
+			elog(DEBUG1, "defineVariable name: %s", name);
+			winstate->defineVariableList = lappend(winstate->defineVariableList,
+												   makeString(pstrdup(name)));
+			attno_map((Node *)expr);
+			exps = ExecInitExpr(expr, (PlanState *) winstate);
+			winstate->defineClauseList = lappend(winstate->defineClauseList, exps);
+		}
+	}
+
 	winstate->all_first = true;
 	winstate->partition_spooled = false;
 	winstate->more_partitions = false;
@@ -2674,6 +2827,57 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags)
 	return winstate;
 }
 
+/*
+ * Rewrite varno of Var node that is the argument of PREV/NET so that it sees
+ * scan tuple (PREV) or inner tuple (NEXT).
+ */
+static void
+attno_map(Node *node)
+{
+	(void) expression_tree_walker(node, attno_map_walker, NULL);
+}
+
+static bool
+attno_map_walker(Node *node, void *context)
+{
+	FuncExpr	*func;
+	int			nargs;
+	Expr		*expr;
+	Var			*var;
+
+	if (node == NULL)
+		return false;
+
+	if (IsA(node, FuncExpr))
+	{
+		func = (FuncExpr *)node;
+
+		if (func->funcid == F_PREV || func->funcid == F_NEXT)
+		{
+			/* sanity check */
+			nargs = list_length(func->args);
+			if (list_length(func->args) != 1)
+				elog(ERROR, "PREV/NEXT must have 1 argument but function %d has %d args", func->funcid, nargs);
+
+			expr = (Expr *) lfirst(list_head(func->args));
+			if (!IsA(expr, Var))
+				elog(ERROR, "PREV/NEXT's arg is not Var");	/* XXX: is it possible that arg type is Const? */
+			var = (Var *)expr;
+
+			if (func->funcid == F_PREV)
+				/*
+				 * Rewrite varno from OUTER_VAR to regular var no so that the
+				 * var references scan tuple.
+				 */
+				var->varno = var->varnosyn;
+			else
+				var->varno = INNER_VAR;
+			elog(DEBUG1, "PREV/NEXT's varno is rewritten to: %d", var->varno);
+		}
+	}
+	return expression_tree_walker(node, attno_map_walker, NULL);
+}
+
 /* -----------------
  * ExecEndWindowAgg
  * -----------------
@@ -2691,6 +2895,8 @@ ExecEndWindowAgg(WindowAggState *node)
 	ExecClearTuple(node->agg_row_slot);
 	ExecClearTuple(node->temp_slot_1);
 	ExecClearTuple(node->temp_slot_2);
+	ExecClearTuple(node->prev_slot);
+	ExecClearTuple(node->next_slot);
 	if (node->framehead_slot)
 		ExecClearTuple(node->framehead_slot);
 	if (node->frametail_slot)
@@ -2740,6 +2946,8 @@ ExecReScanWindowAgg(WindowAggState *node)
 	ExecClearTuple(node->agg_row_slot);
 	ExecClearTuple(node->temp_slot_1);
 	ExecClearTuple(node->temp_slot_2);
+	ExecClearTuple(node->prev_slot);
+	ExecClearTuple(node->next_slot);
 	if (node->framehead_slot)
 		ExecClearTuple(node->framehead_slot);
 	if (node->frametail_slot)
@@ -3100,7 +3308,7 @@ window_gettupleslot(WindowObject winobj, int64 pos, TupleTableSlot *slot)
 		return false;
 
 	if (pos < winobj->markpos)
-		elog(ERROR, "cannot fetch row before WindowObject's mark position");
+		elog(ERROR, "cannot fetch row: " INT64_FORMAT " before WindowObject's mark position: " INT64_FORMAT,  pos, winobj->markpos );
 
 	oldcontext = MemoryContextSwitchTo(winstate->ss.ps.ps_ExprContext->ecxt_per_query_memory);
 
@@ -3420,14 +3628,54 @@ WinGetFuncArgInFrame(WindowObject winobj, int argno,
 	WindowAggState *winstate;
 	ExprContext *econtext;
 	TupleTableSlot *slot;
-	int64		abs_pos;
-	int64		mark_pos;
 
 	Assert(WindowObjectIsValid(winobj));
 	winstate = winobj->winstate;
 	econtext = winstate->ss.ps.ps_ExprContext;
 	slot = winstate->temp_slot_1;
 
+	if (WinGetSlotInFrame(winobj, slot,
+						  relpos, seektype, set_mark,
+						  isnull, isout) == 0)
+	{
+		econtext->ecxt_outertuple = slot;
+		return ExecEvalExpr((ExprState *) list_nth(winobj->argstates, argno),
+							econtext, isnull);
+	}
+
+	if (isout)
+		*isout = true;
+	*isnull = true;
+	return (Datum) 0;
+}
+
+/*
+ * WinGetSlotInFrame
+ * slot: TupleTableSlot to store the result
+ * relpos: signed rowcount offset from the seek position
+ * seektype: WINDOW_SEEK_HEAD or WINDOW_SEEK_TAIL
+ * set_mark: If the row is found/in frame and set_mark is true, the mark is
+ *		moved to the row as a side-effect.
+ * isnull: output argument, receives isnull status of result
+ * isout: output argument, set to indicate whether target row position
+ *		is out of frame (can pass NULL if caller doesn't care about this)
+ *
+ * Returns 0 if we successfullt got the slot. false if out of frame.
+ * (also isout is set)
+ */
+static int
+WinGetSlotInFrame(WindowObject winobj, TupleTableSlot *slot,
+					 int relpos, int seektype, bool set_mark,
+					 bool *isnull, bool *isout)
+{
+	WindowAggState *winstate;
+	int64		abs_pos;
+	int64		mark_pos;
+	int			num_reduced_frame;
+
+	Assert(WindowObjectIsValid(winobj));
+	winstate = winobj->winstate;
+
 	switch (seektype)
 	{
 		case WINDOW_SEEK_CURRENT:
@@ -3494,11 +3742,21 @@ WinGetFuncArgInFrame(WindowObject winobj, int argno,
 						 winstate->frameOptions);
 					break;
 			}
+			num_reduced_frame = row_is_in_reduced_frame(winobj, winstate->frameheadpos);
+			if (num_reduced_frame < 0)
+				goto out_of_frame;
+			else if (num_reduced_frame > 0)
+				if (relpos >= num_reduced_frame)
+					goto out_of_frame;
 			break;
 		case WINDOW_SEEK_TAIL:
 			/* rejecting relpos > 0 is easy and simplifies code below */
 			if (relpos > 0)
 				goto out_of_frame;
+
+			/* RPR cares about frame head pos. Need to call update_frameheadpos */
+			update_frameheadpos(winstate);
+
 			update_frametailpos(winstate);
 			abs_pos = winstate->frametailpos - 1 + relpos;
 
@@ -3565,6 +3823,12 @@ WinGetFuncArgInFrame(WindowObject winobj, int argno,
 					mark_pos = 0;	/* keep compiler quiet */
 					break;
 			}
+
+			num_reduced_frame = row_is_in_reduced_frame(winobj, winstate->frameheadpos + relpos);
+			if (num_reduced_frame < 0)
+				goto out_of_frame;
+			else if (num_reduced_frame > 0)
+				abs_pos = winstate->frameheadpos + relpos + num_reduced_frame - 1;
 			break;
 		default:
 			elog(ERROR, "unrecognized window seek type: %d", seektype);
@@ -3583,15 +3847,13 @@ WinGetFuncArgInFrame(WindowObject winobj, int argno,
 		*isout = false;
 	if (set_mark)
 		WinSetMarkPosition(winobj, mark_pos);
-	econtext->ecxt_outertuple = slot;
-	return ExecEvalExpr((ExprState *) list_nth(winobj->argstates, argno),
-						econtext, isnull);
+	return 0;
 
 out_of_frame:
 	if (isout)
 		*isout = true;
 	*isnull = true;
-	return (Datum) 0;
+	return -1;
 }
 
 /*
@@ -3622,3 +3884,572 @@ WinGetFuncArgCurrent(WindowObject winobj, int argno, bool *isnull)
 	return ExecEvalExpr((ExprState *) list_nth(winobj->argstates, argno),
 						econtext, isnull);
 }
+
+/*
+ * rpr_is_defined
+ * return true if Row pattern recognition is defined.
+ */
+static
+bool rpr_is_defined(WindowAggState *winstate)
+{
+	return winstate->patternVariableList != NIL;
+}
+
+/*
+ * row_is_in_reduced_frame
+ * Determine whether a row is in the current row's reduced window frame according
+ * to row pattern matching
+ *
+ * The row must has been already determined that it is in a full window frame
+ * and fetched it into slot.
+ *
+ * Returns:
+ * = 0, RPR is not defined.
+ * >0, if the row is the first in the reduced frame. Return the number of rows in the reduced frame.
+ * -1, if the row is unmatched row
+ * -2, if the row is in the reduced frame but needed to be skipped because of
+ * AFTER MATCH SKIP PAST LAST ROW
+ */
+static
+int row_is_in_reduced_frame(WindowObject winobj, int64 pos)
+{
+	WindowAggState *winstate = winobj->winstate;
+	int		state;
+	int		rtn;
+
+	if (!rpr_is_defined(winstate))
+	{
+		/*
+		 * RPR is not defined. Assume that we are always in the the reduced
+		 * window frame.
+		 */
+		rtn = 0;
+		elog(DEBUG1, "row_is_in_reduced_frame returns %d: pos: " INT64_FORMAT, rtn, pos);
+		return rtn;
+	}
+
+	state = get_reduced_frame_map(winstate, pos);
+
+	if (state == RF_NOT_DETERMINED)
+	{
+		update_frameheadpos(winstate);
+		update_reduced_frame(winobj, pos);
+	}
+
+	state = get_reduced_frame_map(winstate, pos);
+
+	switch (state)
+	{
+		int64	i;
+		int		num_reduced_rows;
+
+		case RF_FRAME_HEAD:
+			num_reduced_rows = 1;
+			for (i = pos + 1; get_reduced_frame_map(winstate,i) == RF_SKIPPED; i++)
+				num_reduced_rows++;
+			rtn = num_reduced_rows;
+			break;
+
+		case RF_SKIPPED:
+			rtn = -2;
+			break;
+
+		case RF_UNMATCHED:
+			rtn = -1;
+			break;
+
+		default:
+			elog(ERROR, "Unrecognized state: %d at: " INT64_FORMAT, state, pos);
+			break;
+	}
+
+	elog(DEBUG1, "row_is_in_reduced_frame returns %d: pos: " INT64_FORMAT, rtn, pos);
+	return rtn;
+}
+
+#define REDUCED_FRAME_MAP_INIT_SIZE	1024L
+
+/*
+ * Create reduced frame map
+ */
+static
+void create_reduced_frame_map(WindowAggState *winstate)
+{
+	winstate->reduced_frame_map =
+		MemoryContextAlloc(winstate->partcontext, REDUCED_FRAME_MAP_INIT_SIZE);
+	winstate->alloc_sz = REDUCED_FRAME_MAP_INIT_SIZE;
+	clear_reduced_frame_map(winstate);
+}
+
+/*
+ * Clear reduced frame map
+ */
+static
+void clear_reduced_frame_map(WindowAggState *winstate)
+{
+	Assert(winstate->reduced_frame_map != NULL);
+	MemSet(winstate->reduced_frame_map, RF_NOT_DETERMINED,
+		   winstate->alloc_sz);
+}
+
+/*
+ * Get reduced frame map specified by pos
+ */
+static
+int get_reduced_frame_map(WindowAggState *winstate, int64 pos)
+{
+	Assert(winstate->reduced_frame_map != NULL);
+
+	if (pos < 0 || pos >= winstate->alloc_sz)
+		elog(ERROR, "wrong pos: " INT64_FORMAT, pos);
+
+	return winstate->reduced_frame_map[pos];
+}
+
+/*
+ * Add/replace reduced frame map member at pos.
+ * If there's no enough space, expand the map.
+ */
+static
+void register_reduced_frame_map(WindowAggState *winstate, int64 pos, int val)
+{
+	int64	realloc_sz;
+
+	Assert(winstate->reduced_frame_map != NULL);
+
+	if (pos < 0)
+		elog(ERROR, "wrong pos: " INT64_FORMAT, pos);
+
+	if (pos > winstate->alloc_sz - 1)
+	{
+		realloc_sz = winstate->alloc_sz * 2;
+
+		winstate->reduced_frame_map =
+			repalloc(winstate->reduced_frame_map, realloc_sz);
+
+		MemSet(winstate->reduced_frame_map + winstate->alloc_sz,
+			   RF_NOT_DETERMINED, realloc_sz - winstate->alloc_sz);
+
+		winstate->alloc_sz = realloc_sz;
+	}
+
+	winstate->reduced_frame_map[pos] = val;
+}
+
+/*
+ * update_reduced_frame
+ *		Update reduced frame info.
+ */
+static
+void update_reduced_frame(WindowObject winobj, int64 pos)
+{
+	WindowAggState *winstate = winobj->winstate;
+	ListCell	*lc1, *lc2;
+	bool		expression_result;
+	int			num_matched_rows;
+	int64		original_pos;
+	bool		anymatch;
+	StringInfo	encoded_str;
+	StringInfo	pattern_str = makeStringInfo();
+
+	/*
+	 * Array of pattern variables evaluted to true.
+	 * Each character corresponds to pattern variable.
+	 * Example:
+	 * str_set[0] = "AB";
+	 * str_set[1] = "AC";
+	 * In this case at row 0 A and B are true, and A and C are true in row 1.
+	 */
+	#define ENCODED_STR_ARRAY_ALLOC_SIZE	128
+	StringInfo	*str_set = NULL;
+	int		str_set_index;
+	int		str_set_size;
+
+	/* save original pos */
+	original_pos = pos;
+
+	/*
+	 * Loop over until none of pattern matches or encounters end of frame.
+	 */
+	for (;;)
+	{
+		int64	result_pos = -1;
+
+		/*
+		 * Loop over each PATTERN variable.
+		 */
+		anymatch = false;
+		encoded_str = makeStringInfo();
+
+		forboth(lc1, winstate->patternVariableList, lc2, winstate->patternRegexpList)
+		{
+			char	*vname = strVal(lfirst(lc1));
+			char	*quantifier = strVal(lfirst(lc2));
+
+			elog(DEBUG1, "pos: " INT64_FORMAT " pattern vname: %s quantifier: %s", pos, vname, quantifier);
+
+			expression_result = false;
+
+			/* evaluate row pattern against current row */
+			result_pos = evaluate_pattern(winobj, pos, vname, encoded_str, &expression_result);
+			if (expression_result)
+			{
+				elog(DEBUG1, "expression result is true");
+				anymatch = true;
+			}
+
+			/*
+			 * If out of frame, we are done.
+			 */
+			 if (result_pos < 0)
+				 break;
+		}
+
+		if (!anymatch)
+		{
+			/* none of patterns matched. */
+			break;
+		}
+
+		/* build encoded string array */
+		if (str_set == NULL)
+		{
+			str_set_index = 0;
+			str_set_size = ENCODED_STR_ARRAY_ALLOC_SIZE * sizeof(StringInfo);
+			str_set = palloc(str_set_size);
+		}
+
+		str_set[str_set_index++] = encoded_str;
+
+		elog(DEBUG1, "pos: " INT64_FORMAT " str_set_index: %d encoded_str: %s", pos, str_set_index, encoded_str->data);
+
+		if (str_set_index >= str_set_size)
+		{
+			str_set_size *= 2;
+			str_set = repalloc(str_set, str_set_size);
+		}
+
+		/* move to next row */
+		pos++;
+
+		if (result_pos < 0)
+		{
+			/* out of frame */
+			break;
+		}
+	}
+
+	if (str_set == NULL)
+	{
+		/* no match found in the first row */
+		register_reduced_frame_map(winstate, original_pos, RF_UNMATCHED);
+		return;
+	}
+
+	elog(DEBUG2, "pos: " INT64_FORMAT " encoded_str: %s", pos, encoded_str->data);
+
+	/* build regular expression */
+	pattern_str = makeStringInfo();
+	appendStringInfoChar(pattern_str, '^');
+	forboth (lc1, winstate->patternVariableList, lc2, winstate->patternRegexpList)
+	{
+		char	*vname = strVal(lfirst(lc1));
+		char	*quantifier = strVal(lfirst(lc2));
+		char	 initial;
+
+		initial = pattern_initial(winstate, vname);
+		Assert(initial != 0);
+		appendStringInfoChar(pattern_str, initial);
+		if (quantifier[0])
+			appendStringInfoChar(pattern_str, quantifier[0]);
+		elog(DEBUG1, "vname: %s initial: %c quantifier: %s", vname, initial, quantifier);
+	}
+
+	elog(DEBUG2, "pos: " INT64_FORMAT " pattern: %s", pos, pattern_str->data);
+
+	/* look for matching pattern variable sequence */
+	num_matched_rows = search_str_set(pattern_str->data, str_set, str_set_index);
+	/*
+	 * We are at the first row in the reduced frame.  Save the number of
+	 * matched rows as the number of rows in the reduced frame.
+	 */
+	if (num_matched_rows <= 0)
+	{
+		/* no match */
+		register_reduced_frame_map(winstate, original_pos, RF_UNMATCHED);
+	}
+	else
+	{
+		int64		i;
+
+		register_reduced_frame_map(winstate, original_pos, RF_FRAME_HEAD);
+
+		for (i = original_pos + 1; i < original_pos + num_matched_rows; i++)
+		{
+			register_reduced_frame_map(winstate, i, RF_SKIPPED);
+		}
+	}
+
+	return;
+}
+
+/*
+ * Perform regex search pattern against encoded string array str_set.
+ * returns the number of longest matching rows.
+ * str_set: array of encoded string. Each array element corresponds to each
+ * row.
+ * set_size: size of set_str array.
+ */
+static
+int search_str_set(char *pattern, StringInfo *str_set, int set_size)
+{
+	char		*encoded_str = palloc0(set_size+1);
+	int			resultlen = 0;
+
+	search_str_set_recurse(pattern, str_set, set_size, 0, 0,
+						   encoded_str, &resultlen);
+	elog(DEBUG1, "search_str_set returns %d", resultlen);
+	return resultlen;
+}
+
+/*
+ * Workhorse of search_str_set.
+ *
+ * Recurse among matched pattern variables in a row.  The max recursion depth
+ * is number of pattern variables matched in a row.
+ */
+static
+void search_str_set_recurse(char *pattern, StringInfo *str_set,
+							int set_size, int set_index, int str_index,
+							char *encoded_str, int *resultlen)
+{
+	for (;;)
+	{
+		char	c;
+
+		c = str_set[set_index]->data[str_index];
+		if (c == '\0')
+			return;
+		encoded_str[set_index] = c;
+		set_index++;
+
+		if (set_index >= set_size)
+		{
+			Datum	d;
+			text	*res;
+			char	*substr;
+
+			/*
+			 * We first perform pattern matching using regexp_instr, then call
+			 * textregexsubstr to get matched substring to know how long the
+			 * matched string is. That is the number of rows in the reduced window
+			 * frame.  The reason why we can't call textregexsubstr in the first
+			 * place is, it errors out if pattern does not match.
+			 */
+			if (DatumGetInt32(DirectFunctionCall2Coll(regexp_instr, DEFAULT_COLLATION_OID,
+													  PointerGetDatum(cstring_to_text(encoded_str)),
+													  PointerGetDatum(cstring_to_text(pattern)))) > 0)
+			{
+				d = DirectFunctionCall2Coll(textregexsubstr,
+											DEFAULT_COLLATION_OID,
+											PointerGetDatum(cstring_to_text(encoded_str)),
+											PointerGetDatum(cstring_to_text(pattern)));
+				if (d != 0)
+				{
+					int		len;
+
+					res = DatumGetTextPP(d);
+					substr = text_to_cstring(res);
+					len = strlen(substr);
+					if (len > *resultlen)
+						/* remember the longest match */
+						*resultlen = len;
+				}
+			}
+			return;
+		}
+		else
+			search_str_set_recurse(pattern, str_set, set_size, set_index, str_index + 1,
+								   encoded_str, resultlen);
+	}
+}
+
+/*
+ * Evaluate expression associated with PATTERN variable vname.
+ * relpos is relative row position in a frame (starting from 0).
+ * "quantifier" is the quatifier part of the PATTERN regular expression.
+ * Currently only '+' is allowed.
+ * result is out paramater representing the expression evaluation result
+ * is true of false.
+ * Return values are:
+ * >=0: the last match absolute row position
+ * other wise out of frame.
+ */
+static
+int64 evaluate_pattern(WindowObject winobj, int64 current_pos,
+						char *vname, StringInfo encoded_str, bool *result)
+{
+	WindowAggState	*winstate = winobj->winstate;
+	ExprContext		*econtext = winstate->ss.ps.ps_ExprContext;
+	ListCell		*lc1, *lc2, *lc3;
+	ExprState		*pat;
+	Datum			eval_result;
+	bool			out_of_frame = false;
+	bool			isnull;
+
+	forthree (lc1, winstate->defineVariableList, lc2, winstate->defineClauseList, lc3, winstate->defineInitial)
+	{
+		char	initial;
+		char	*name = strVal(lfirst(lc1));
+
+		if (strcmp(vname, name))
+			continue;
+
+		initial = *(strVal(lfirst(lc3)));
+
+		/* set expression to evaluate */
+		pat = lfirst(lc2);
+
+		/* get current, previous and next tuples */
+		if (!get_slots(winobj, current_pos))
+		{
+			out_of_frame = true;
+		}
+		else
+		{
+			/* evaluate the expression */
+			eval_result = ExecEvalExpr(pat, econtext, &isnull);
+			if (isnull)
+			{
+				/* expression is NULL */
+				elog(DEBUG1, "expression for %s is NULL at row: " INT64_FORMAT, vname, current_pos);
+				*result = false;
+			}
+			else
+			{
+				if (!DatumGetBool(eval_result))
+				{
+					/* expression is false */
+					elog(DEBUG1, "expression for %s is false at row: " INT64_FORMAT, vname, current_pos);
+					*result = false;
+				}
+				else
+				{
+					/* expression is true */
+					elog(DEBUG1, "expression for %s is true at row: " INT64_FORMAT, vname, current_pos);
+					appendStringInfoChar(encoded_str, initial);
+					*result = true;
+				}
+			}
+			break;
+		}
+
+		if (out_of_frame)
+		{
+			*result = false;
+			return -1;
+		}
+	}
+	return current_pos;
+}
+
+/*
+ * Get current, previous and next tuples.
+ * Returns false if current row is out of partition/full frame.
+ */
+static
+bool get_slots(WindowObject winobj, int64 current_pos)
+{
+	WindowAggState *winstate = winobj->winstate;
+	TupleTableSlot *slot;
+	int		ret;
+	ExprContext *econtext;
+
+	econtext = winstate->ss.ps.ps_ExprContext;
+
+	/* set up current row tuple slot */
+	slot = winstate->temp_slot_1;
+	if (!window_gettupleslot(winobj, current_pos, slot))
+	{
+		elog(DEBUG1, "current row is out of partition at:" INT64_FORMAT, current_pos);
+		return false;
+
+		ret = row_is_in_frame(winstate, current_pos, slot);
+		if (ret <= 0)
+		{
+			elog(DEBUG1, "current row is out of frame at: " INT64_FORMAT, current_pos);
+			return false;
+		}
+	}
+	econtext->ecxt_outertuple = slot;
+
+	/* for PREV */
+	if (current_pos > 0)
+	{
+		slot = winstate->prev_slot;
+		if (!window_gettupleslot(winobj, current_pos - 1, slot))
+		{
+			elog(DEBUG1, "previous row is out of partition at: " INT64_FORMAT, current_pos - 1);
+			econtext->ecxt_scantuple = winstate->null_slot;
+		}
+		else
+		{
+			ret = row_is_in_frame(winstate, current_pos - 1, slot);
+			if (ret <= 0)
+			{
+				elog(DEBUG1, "previous row is out of frame at: " INT64_FORMAT, current_pos - 1);
+				econtext->ecxt_scantuple = winstate->null_slot;
+			}
+			else
+			{
+				econtext->ecxt_scantuple = slot;
+			}
+		}
+	}
+	else
+		econtext->ecxt_scantuple = winstate->null_slot;
+
+	/* for NEXT */
+	slot = winstate->next_slot;
+	if (!window_gettupleslot(winobj, current_pos + 1, slot))
+	{
+		elog(DEBUG1, "next row is out of partiton at: " INT64_FORMAT, current_pos + 1);
+		econtext->ecxt_innertuple = winstate->null_slot;
+	}
+	else
+	{
+		ret = row_is_in_frame(winstate, current_pos + 1, slot);
+		if (ret <= 0)
+		{
+			elog(DEBUG1, "next row is out of frame at: " INT64_FORMAT, current_pos + 1);
+			econtext->ecxt_innertuple = winstate->null_slot;
+		}
+		else
+			econtext->ecxt_innertuple = slot;
+	}
+	return true;
+}
+
+/*
+ * Return pattern variable initial character
+ * matching with pattern variable name vname.
+ * If not found, return 0.
+ */
+static
+char	pattern_initial(WindowAggState *winstate, char *vname)
+{
+	char		initial;
+	char		*name;
+	ListCell	*lc1, *lc2;
+
+	forboth (lc1, winstate->defineVariableList, lc2, winstate->defineInitial)
+	{
+		name = strVal(lfirst(lc1));				/* DEFINE variable name */
+		initial = *(strVal(lfirst(lc2)));		/* DEFINE variable initial */
+
+
+		if (!strcmp(name, vname))
+				return initial;					/* found */
+	}
+	return 0;
+}
diff --git a/src/backend/utils/adt/windowfuncs.c b/src/backend/utils/adt/windowfuncs.c
index b87a624fb2..9ebcc7b5d2 100644
--- a/src/backend/utils/adt/windowfuncs.c
+++ b/src/backend/utils/adt/windowfuncs.c
@@ -13,6 +13,9 @@
  */
 #include "postgres.h"
 
+#include "catalog/pg_collation_d.h"
+#include "executor/executor.h"
+#include "nodes/execnodes.h"
 #include "nodes/supportnodes.h"
 #include "utils/builtins.h"
 #include "windowapi.h"
@@ -36,11 +39,19 @@ typedef struct
 	int64		remainder;		/* (total rows) % (bucket num) */
 } ntile_context;
 
+/*
+ * rpr process information.
+ * Used for AFTER MATCH SKIP PAST LAST ROW
+ */
+typedef struct SkipContext
+{
+	int64		pos;	/* last row absolute position */
+} SkipContext;
+
 static bool rank_up(WindowObject winobj);
 static Datum leadlag_common(FunctionCallInfo fcinfo,
 							bool forward, bool withoffset, bool withdefault);
 
-
 /*
  * utility routine for *_rank functions.
  */
@@ -673,7 +684,7 @@ window_last_value(PG_FUNCTION_ARGS)
 	bool		isnull;
 
 	result = WinGetFuncArgInFrame(winobj, 0,
-								  0, WINDOW_SEEK_TAIL, true,
+								  0, WINDOW_SEEK_TAIL, false,
 								  &isnull, NULL);
 	if (isnull)
 		PG_RETURN_NULL();
@@ -713,3 +724,25 @@ window_nth_value(PG_FUNCTION_ARGS)
 
 	PG_RETURN_DATUM(result);
 }
+
+/*
+ * prev
+ * Dummy function to invoke RPR's navigation operator "PREV".
+ * This is *not* a window function.
+ */
+Datum
+window_prev(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_DATUM(PG_GETARG_DATUM(0));
+}
+
+/*
+ * next
+ * Dummy function to invoke RPR's navigation operation "NEXT".
+ * This is *not* a window function.
+ */
+Datum
+window_next(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_DATUM(PG_GETARG_DATUM(0));
+}
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 9805bc6118..d20f803cf5 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -10416,6 +10416,12 @@
 { oid => '3114', descr => 'fetch the Nth row value',
   proname => 'nth_value', prokind => 'w', prorettype => 'anyelement',
   proargtypes => 'anyelement int4', prosrc => 'window_nth_value' },
+{ oid => '6122', descr => 'previous value',
+  proname => 'prev', provolatile => 's', prorettype => 'anyelement',
+  proargtypes => 'anyelement', prosrc => 'window_prev' },
+{ oid => '6123', descr => 'next value',
+  proname => 'next', provolatile => 's', prorettype => 'anyelement',
+  proargtypes => 'anyelement', prosrc => 'window_next' },
 
 # functions for range types
 { oid => '3832', descr => 'I/O',
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index cb714f4a19..63feb68f60 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -2471,6 +2471,11 @@ typedef enum WindowAggStatus
 									 * tuples during spool */
 } WindowAggStatus;
 
+#define	RF_NOT_DETERMINED	0
+#define	RF_FRAME_HEAD		1
+#define	RF_SKIPPED			2
+#define	RF_UNMATCHED		3
+
 typedef struct WindowAggState
 {
 	ScanState	ss;				/* its first field is NodeTag */
@@ -2519,6 +2524,15 @@ typedef struct WindowAggState
 	int64		groupheadpos;	/* current row's peer group head position */
 	int64		grouptailpos;	/* " " " " tail position (group end+1) */
 
+	/* these fields are used in Row pattern recognition: */
+	RPSkipTo	rpSkipTo;		/* Row Pattern Skip To type */
+	List	   *patternVariableList;	/* list of row pattern variables names (list of String) */
+	List	   *patternRegexpList;	/* list of row pattern regular expressions ('+' or ''. list of String) */
+	List	   *defineVariableList;	/* list of row pattern definition variables (list of String) */
+	List	   *defineClauseList;	/* expression for row pattern definition
+									 * search conditions ExprState list */
+	List	   *defineInitial;		/* list of row pattern definition variable initials (list of String) */
+
 	MemoryContext partcontext;	/* context for partition-lifespan data */
 	MemoryContext aggcontext;	/* shared context for aggregate working data */
 	MemoryContext curaggcontext;	/* current aggregate's working data */
@@ -2555,6 +2569,18 @@ typedef struct WindowAggState
 	TupleTableSlot *agg_row_slot;
 	TupleTableSlot *temp_slot_1;
 	TupleTableSlot *temp_slot_2;
+
+	/* temporary slots for RPR */
+	TupleTableSlot *prev_slot;	/* PREV row navigation operator */
+	TupleTableSlot *next_slot;	/* NEXT row navigation operator */
+	TupleTableSlot *null_slot;	/* all NULL slot */
+
+	/*
+	 * Each byte corresponds to a row positioned at absolute its pos in
+	 * partition.  See above definition for RF_*
+	 */
+	char		*reduced_frame_map;
+	int64		alloc_sz;	/* size of the map */
 } WindowAggState;
 
 /* ----------------
-- 
2.25.1


----Next_Part(Fri_Sep_22_14_16_40_2023_530)--
Content-Type: Text/X-Patch; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="v7-0005-Row-pattern-recognition-patch-docs.patch"



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v37 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 src/test/isolation/isolation_schedule         |    9 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 4 files changed, 1690 insertions(+)
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index 15c33fad4c5..111fd465207 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -127,3 +127,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__29_May_2026_23_14_17_+0900_Te0o73X2VqYK57Gd
Content-Type: text/x-diff;
 name="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v39 7/8] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  | 285 ++++++++
 .../isolation/expected/ivm-create-insert2.out | 305 ++++++++
 .../isolation/expected/ivm-create-insert3.out | 305 ++++++++
 .../isolation/expected/ivm-insert-insert.out  | 497 +++++++++++++
 .../isolation/expected/ivm-insert-insert2.out | 373 ++++++++++
 .../isolation/expected/ivm-insert-insert3.out | 373 ++++++++++
 .../isolation/expected/ivm-refresh-insert.out | 213 ++++++
 .../expected/ivm-refresh-insert2.out          | 191 +++++
 .../expected/ivm-refresh-insert3.out          | 191 +++++
 src/test/isolation/isolation_schedule         |   9 +
 .../isolation/specs/ivm-create-insert.spec    |  47 ++
 .../isolation/specs/ivm-create-insert2.spec   |  54 ++
 .../isolation/specs/ivm-create-insert3.spec   |  54 ++
 .../isolation/specs/ivm-insert-insert.spec    |  62 ++
 .../isolation/specs/ivm-insert-insert2.spec   |  62 ++
 .../isolation/specs/ivm-insert-insert3.spec   |  62 ++
 .../isolation/specs/ivm-refresh-insert.spec   |  46 ++
 .../isolation/specs/ivm-refresh-insert2.spec  |  46 ++
 .../isolation/specs/ivm-refresh-insert3.spec  |  46 ++
 .../regress/expected/incremental_matview.out  | 667 ++++++++++++++++++
 src/test/regress/parallel_schedule            |   1 +
 src/test/regress/sql/incremental_matview.sql  | 407 +++++++++++
 22 files changed, 4296 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..c7fd19fdca3
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,667 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..7313ad82f3e
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,407 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ROLLBACK;
+
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__3_Jul_2026_19_11_16_+0900_CskxSIu_iGcDMEyM
Content-Type: text/x-diff;
 name="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Disposition: attachment;
 filename="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v39 7/8] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  | 285 ++++++++
 .../isolation/expected/ivm-create-insert2.out | 305 ++++++++
 .../isolation/expected/ivm-create-insert3.out | 305 ++++++++
 .../isolation/expected/ivm-insert-insert.out  | 497 +++++++++++++
 .../isolation/expected/ivm-insert-insert2.out | 373 ++++++++++
 .../isolation/expected/ivm-insert-insert3.out | 373 ++++++++++
 .../isolation/expected/ivm-refresh-insert.out | 213 ++++++
 .../expected/ivm-refresh-insert2.out          | 191 +++++
 .../expected/ivm-refresh-insert3.out          | 191 +++++
 src/test/isolation/isolation_schedule         |   9 +
 .../isolation/specs/ivm-create-insert.spec    |  47 ++
 .../isolation/specs/ivm-create-insert2.spec   |  54 ++
 .../isolation/specs/ivm-create-insert3.spec   |  54 ++
 .../isolation/specs/ivm-insert-insert.spec    |  62 ++
 .../isolation/specs/ivm-insert-insert2.spec   |  62 ++
 .../isolation/specs/ivm-insert-insert3.spec   |  62 ++
 .../isolation/specs/ivm-refresh-insert.spec   |  46 ++
 .../isolation/specs/ivm-refresh-insert2.spec  |  46 ++
 .../isolation/specs/ivm-refresh-insert3.spec  |  46 ++
 .../regress/expected/incremental_matview.out  | 667 ++++++++++++++++++
 src/test/regress/parallel_schedule            |   1 +
 src/test/regress/sql/incremental_matview.sql  | 407 +++++++++++
 22 files changed, 4296 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..c7fd19fdca3
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,667 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..7313ad82f3e
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,407 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ROLLBACK;
+
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__3_Jul_2026_19_11_16_+0900_CskxSIu_iGcDMEyM
Content-Type: text/x-diff;
 name="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Disposition: attachment;
 filename="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v38 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  |  285 +++++
 .../isolation/expected/ivm-create-insert2.out |  305 +++++
 .../isolation/expected/ivm-create-insert3.out |  305 +++++
 .../isolation/expected/ivm-insert-insert.out  |  497 ++++++++
 .../isolation/expected/ivm-insert-insert2.out |  373 ++++++
 .../isolation/expected/ivm-insert-insert3.out |  373 ++++++
 .../isolation/expected/ivm-refresh-insert.out |  213 ++++
 .../expected/ivm-refresh-insert2.out          |  191 +++
 .../expected/ivm-refresh-insert3.out          |  191 +++
 src/test/isolation/isolation_schedule         |    9 +
 .../isolation/specs/ivm-create-insert.spec    |   47 +
 .../isolation/specs/ivm-create-insert2.spec   |   54 +
 .../isolation/specs/ivm-create-insert3.spec   |   54 +
 .../isolation/specs/ivm-insert-insert.spec    |   62 +
 .../isolation/specs/ivm-insert-insert2.spec   |   62 +
 .../isolation/specs/ivm-insert-insert3.spec   |   62 +
 .../isolation/specs/ivm-refresh-insert.spec   |   46 +
 .../isolation/specs/ivm-refresh-insert2.spec  |   46 +
 .../isolation/specs/ivm-refresh-insert3.spec  |   46 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 22 files changed, 4902 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Wed__1_Jul_2026_00_04_01_+0900_OVSy2WWK_9aByzDJ
Content-Type: text/x-diff;
 name="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v38 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  |  285 +++++
 .../isolation/expected/ivm-create-insert2.out |  305 +++++
 .../isolation/expected/ivm-create-insert3.out |  305 +++++
 .../isolation/expected/ivm-insert-insert.out  |  497 ++++++++
 .../isolation/expected/ivm-insert-insert2.out |  373 ++++++
 .../isolation/expected/ivm-insert-insert3.out |  373 ++++++
 .../isolation/expected/ivm-refresh-insert.out |  213 ++++
 .../expected/ivm-refresh-insert2.out          |  191 +++
 .../expected/ivm-refresh-insert3.out          |  191 +++
 src/test/isolation/isolation_schedule         |    9 +
 .../isolation/specs/ivm-create-insert.spec    |   47 +
 .../isolation/specs/ivm-create-insert2.spec   |   54 +
 .../isolation/specs/ivm-create-insert3.spec   |   54 +
 .../isolation/specs/ivm-insert-insert.spec    |   62 +
 .../isolation/specs/ivm-insert-insert2.spec   |   62 +
 .../isolation/specs/ivm-insert-insert3.spec   |   62 +
 .../isolation/specs/ivm-refresh-insert.spec   |   46 +
 .../isolation/specs/ivm-refresh-insert2.spec  |   46 +
 .../isolation/specs/ivm-refresh-insert3.spec  |   46 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 22 files changed, 4902 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Wed__1_Jul_2026_00_04_01_+0900_OVSy2WWK_9aByzDJ
Content-Type: text/x-diff;
 name="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v39 7/8] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  | 285 ++++++++
 .../isolation/expected/ivm-create-insert2.out | 305 ++++++++
 .../isolation/expected/ivm-create-insert3.out | 305 ++++++++
 .../isolation/expected/ivm-insert-insert.out  | 497 +++++++++++++
 .../isolation/expected/ivm-insert-insert2.out | 373 ++++++++++
 .../isolation/expected/ivm-insert-insert3.out | 373 ++++++++++
 .../isolation/expected/ivm-refresh-insert.out | 213 ++++++
 .../expected/ivm-refresh-insert2.out          | 191 +++++
 .../expected/ivm-refresh-insert3.out          | 191 +++++
 src/test/isolation/isolation_schedule         |   9 +
 .../isolation/specs/ivm-create-insert.spec    |  47 ++
 .../isolation/specs/ivm-create-insert2.spec   |  54 ++
 .../isolation/specs/ivm-create-insert3.spec   |  54 ++
 .../isolation/specs/ivm-insert-insert.spec    |  62 ++
 .../isolation/specs/ivm-insert-insert2.spec   |  62 ++
 .../isolation/specs/ivm-insert-insert3.spec   |  62 ++
 .../isolation/specs/ivm-refresh-insert.spec   |  46 ++
 .../isolation/specs/ivm-refresh-insert2.spec  |  46 ++
 .../isolation/specs/ivm-refresh-insert3.spec  |  46 ++
 .../regress/expected/incremental_matview.out  | 667 ++++++++++++++++++
 src/test/regress/parallel_schedule            |   1 +
 src/test/regress/sql/incremental_matview.sql  | 407 +++++++++++
 22 files changed, 4296 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..c7fd19fdca3
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,667 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..7313ad82f3e
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,407 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ROLLBACK;
+
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__3_Jul_2026_19_11_16_+0900_CskxSIu_iGcDMEyM
Content-Type: text/x-diff;
 name="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Disposition: attachment;
 filename="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v38 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  |  285 +++++
 .../isolation/expected/ivm-create-insert2.out |  305 +++++
 .../isolation/expected/ivm-create-insert3.out |  305 +++++
 .../isolation/expected/ivm-insert-insert.out  |  497 ++++++++
 .../isolation/expected/ivm-insert-insert2.out |  373 ++++++
 .../isolation/expected/ivm-insert-insert3.out |  373 ++++++
 .../isolation/expected/ivm-refresh-insert.out |  213 ++++
 .../expected/ivm-refresh-insert2.out          |  191 +++
 .../expected/ivm-refresh-insert3.out          |  191 +++
 src/test/isolation/isolation_schedule         |    9 +
 .../isolation/specs/ivm-create-insert.spec    |   47 +
 .../isolation/specs/ivm-create-insert2.spec   |   54 +
 .../isolation/specs/ivm-create-insert3.spec   |   54 +
 .../isolation/specs/ivm-insert-insert.spec    |   62 +
 .../isolation/specs/ivm-insert-insert2.spec   |   62 +
 .../isolation/specs/ivm-insert-insert3.spec   |   62 +
 .../isolation/specs/ivm-refresh-insert.spec   |   46 +
 .../isolation/specs/ivm-refresh-insert2.spec  |   46 +
 .../isolation/specs/ivm-refresh-insert3.spec  |   46 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 22 files changed, 4902 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Wed__1_Jul_2026_00_04_01_+0900_OVSy2WWK_9aByzDJ
Content-Type: text/x-diff;
 name="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v39 7/8] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  | 285 ++++++++
 .../isolation/expected/ivm-create-insert2.out | 305 ++++++++
 .../isolation/expected/ivm-create-insert3.out | 305 ++++++++
 .../isolation/expected/ivm-insert-insert.out  | 497 +++++++++++++
 .../isolation/expected/ivm-insert-insert2.out | 373 ++++++++++
 .../isolation/expected/ivm-insert-insert3.out | 373 ++++++++++
 .../isolation/expected/ivm-refresh-insert.out | 213 ++++++
 .../expected/ivm-refresh-insert2.out          | 191 +++++
 .../expected/ivm-refresh-insert3.out          | 191 +++++
 src/test/isolation/isolation_schedule         |   9 +
 .../isolation/specs/ivm-create-insert.spec    |  47 ++
 .../isolation/specs/ivm-create-insert2.spec   |  54 ++
 .../isolation/specs/ivm-create-insert3.spec   |  54 ++
 .../isolation/specs/ivm-insert-insert.spec    |  62 ++
 .../isolation/specs/ivm-insert-insert2.spec   |  62 ++
 .../isolation/specs/ivm-insert-insert3.spec   |  62 ++
 .../isolation/specs/ivm-refresh-insert.spec   |  46 ++
 .../isolation/specs/ivm-refresh-insert2.spec  |  46 ++
 .../isolation/specs/ivm-refresh-insert3.spec  |  46 ++
 .../regress/expected/incremental_matview.out  | 667 ++++++++++++++++++
 src/test/regress/parallel_schedule            |   1 +
 src/test/regress/sql/incremental_matview.sql  | 407 +++++++++++
 22 files changed, 4296 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..c7fd19fdca3
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,667 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..7313ad82f3e
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,407 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ROLLBACK;
+
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__3_Jul_2026_19_11_16_+0900_CskxSIu_iGcDMEyM
Content-Type: text/x-diff;
 name="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Disposition: attachment;
 filename="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v37 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 src/test/isolation/isolation_schedule         |    9 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 4 files changed, 1690 insertions(+)
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index 15c33fad4c5..111fd465207 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -127,3 +127,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__29_May_2026_23_14_17_+0900_Te0o73X2VqYK57Gd
Content-Type: text/x-diff;
 name="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v39 7/8] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  | 285 ++++++++
 .../isolation/expected/ivm-create-insert2.out | 305 ++++++++
 .../isolation/expected/ivm-create-insert3.out | 305 ++++++++
 .../isolation/expected/ivm-insert-insert.out  | 497 +++++++++++++
 .../isolation/expected/ivm-insert-insert2.out | 373 ++++++++++
 .../isolation/expected/ivm-insert-insert3.out | 373 ++++++++++
 .../isolation/expected/ivm-refresh-insert.out | 213 ++++++
 .../expected/ivm-refresh-insert2.out          | 191 +++++
 .../expected/ivm-refresh-insert3.out          | 191 +++++
 src/test/isolation/isolation_schedule         |   9 +
 .../isolation/specs/ivm-create-insert.spec    |  47 ++
 .../isolation/specs/ivm-create-insert2.spec   |  54 ++
 .../isolation/specs/ivm-create-insert3.spec   |  54 ++
 .../isolation/specs/ivm-insert-insert.spec    |  62 ++
 .../isolation/specs/ivm-insert-insert2.spec   |  62 ++
 .../isolation/specs/ivm-insert-insert3.spec   |  62 ++
 .../isolation/specs/ivm-refresh-insert.spec   |  46 ++
 .../isolation/specs/ivm-refresh-insert2.spec  |  46 ++
 .../isolation/specs/ivm-refresh-insert3.spec  |  46 ++
 .../regress/expected/incremental_matview.out  | 667 ++++++++++++++++++
 src/test/regress/parallel_schedule            |   1 +
 src/test/regress/sql/incremental_matview.sql  | 407 +++++++++++
 22 files changed, 4296 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..c7fd19fdca3
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,667 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..7313ad82f3e
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,407 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ROLLBACK;
+
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__3_Jul_2026_19_11_16_+0900_CskxSIu_iGcDMEyM
Content-Type: text/x-diff;
 name="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Disposition: attachment;
 filename="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v37 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 src/test/isolation/isolation_schedule         |    9 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 4 files changed, 1690 insertions(+)
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index 15c33fad4c5..111fd465207 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -127,3 +127,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__29_May_2026_23_14_17_+0900_Te0o73X2VqYK57Gd
Content-Type: text/x-diff;
 name="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v38 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  |  285 +++++
 .../isolation/expected/ivm-create-insert2.out |  305 +++++
 .../isolation/expected/ivm-create-insert3.out |  305 +++++
 .../isolation/expected/ivm-insert-insert.out  |  497 ++++++++
 .../isolation/expected/ivm-insert-insert2.out |  373 ++++++
 .../isolation/expected/ivm-insert-insert3.out |  373 ++++++
 .../isolation/expected/ivm-refresh-insert.out |  213 ++++
 .../expected/ivm-refresh-insert2.out          |  191 +++
 .../expected/ivm-refresh-insert3.out          |  191 +++
 src/test/isolation/isolation_schedule         |    9 +
 .../isolation/specs/ivm-create-insert.spec    |   47 +
 .../isolation/specs/ivm-create-insert2.spec   |   54 +
 .../isolation/specs/ivm-create-insert3.spec   |   54 +
 .../isolation/specs/ivm-insert-insert.spec    |   62 +
 .../isolation/specs/ivm-insert-insert2.spec   |   62 +
 .../isolation/specs/ivm-insert-insert3.spec   |   62 +
 .../isolation/specs/ivm-refresh-insert.spec   |   46 +
 .../isolation/specs/ivm-refresh-insert2.spec  |   46 +
 .../isolation/specs/ivm-refresh-insert3.spec  |   46 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 22 files changed, 4902 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Wed__1_Jul_2026_00_04_01_+0900_OVSy2WWK_9aByzDJ
Content-Type: text/x-diff;
 name="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v37 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 src/test/isolation/isolation_schedule         |    9 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 4 files changed, 1690 insertions(+)
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index 15c33fad4c5..111fd465207 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -127,3 +127,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__29_May_2026_23_14_17_+0900_Te0o73X2VqYK57Gd
Content-Type: text/x-diff;
 name="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v37 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 src/test/isolation/isolation_schedule         |    9 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 4 files changed, 1690 insertions(+)
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index 15c33fad4c5..111fd465207 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -127,3 +127,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__29_May_2026_23_14_17_+0900_Te0o73X2VqYK57Gd
Content-Type: text/x-diff;
 name="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v37 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 src/test/isolation/isolation_schedule         |    9 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 4 files changed, 1690 insertions(+)
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index 15c33fad4c5..111fd465207 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -127,3 +127,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__29_May_2026_23_14_17_+0900_Te0o73X2VqYK57Gd
Content-Type: text/x-diff;
 name="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v38 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  |  285 +++++
 .../isolation/expected/ivm-create-insert2.out |  305 +++++
 .../isolation/expected/ivm-create-insert3.out |  305 +++++
 .../isolation/expected/ivm-insert-insert.out  |  497 ++++++++
 .../isolation/expected/ivm-insert-insert2.out |  373 ++++++
 .../isolation/expected/ivm-insert-insert3.out |  373 ++++++
 .../isolation/expected/ivm-refresh-insert.out |  213 ++++
 .../expected/ivm-refresh-insert2.out          |  191 +++
 .../expected/ivm-refresh-insert3.out          |  191 +++
 src/test/isolation/isolation_schedule         |    9 +
 .../isolation/specs/ivm-create-insert.spec    |   47 +
 .../isolation/specs/ivm-create-insert2.spec   |   54 +
 .../isolation/specs/ivm-create-insert3.spec   |   54 +
 .../isolation/specs/ivm-insert-insert.spec    |   62 +
 .../isolation/specs/ivm-insert-insert2.spec   |   62 +
 .../isolation/specs/ivm-insert-insert3.spec   |   62 +
 .../isolation/specs/ivm-refresh-insert.spec   |   46 +
 .../isolation/specs/ivm-refresh-insert2.spec  |   46 +
 .../isolation/specs/ivm-refresh-insert3.spec  |   46 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 22 files changed, 4902 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Wed__1_Jul_2026_00_04_01_+0900_OVSy2WWK_9aByzDJ
Content-Type: text/x-diff;
 name="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v38 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  |  285 +++++
 .../isolation/expected/ivm-create-insert2.out |  305 +++++
 .../isolation/expected/ivm-create-insert3.out |  305 +++++
 .../isolation/expected/ivm-insert-insert.out  |  497 ++++++++
 .../isolation/expected/ivm-insert-insert2.out |  373 ++++++
 .../isolation/expected/ivm-insert-insert3.out |  373 ++++++
 .../isolation/expected/ivm-refresh-insert.out |  213 ++++
 .../expected/ivm-refresh-insert2.out          |  191 +++
 .../expected/ivm-refresh-insert3.out          |  191 +++
 src/test/isolation/isolation_schedule         |    9 +
 .../isolation/specs/ivm-create-insert.spec    |   47 +
 .../isolation/specs/ivm-create-insert2.spec   |   54 +
 .../isolation/specs/ivm-create-insert3.spec   |   54 +
 .../isolation/specs/ivm-insert-insert.spec    |   62 +
 .../isolation/specs/ivm-insert-insert2.spec   |   62 +
 .../isolation/specs/ivm-insert-insert3.spec   |   62 +
 .../isolation/specs/ivm-refresh-insert.spec   |   46 +
 .../isolation/specs/ivm-refresh-insert2.spec  |   46 +
 .../isolation/specs/ivm-refresh-insert3.spec  |   46 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 22 files changed, 4902 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Wed__1_Jul_2026_00_04_01_+0900_OVSy2WWK_9aByzDJ
Content-Type: text/x-diff;
 name="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v38 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  |  285 +++++
 .../isolation/expected/ivm-create-insert2.out |  305 +++++
 .../isolation/expected/ivm-create-insert3.out |  305 +++++
 .../isolation/expected/ivm-insert-insert.out  |  497 ++++++++
 .../isolation/expected/ivm-insert-insert2.out |  373 ++++++
 .../isolation/expected/ivm-insert-insert3.out |  373 ++++++
 .../isolation/expected/ivm-refresh-insert.out |  213 ++++
 .../expected/ivm-refresh-insert2.out          |  191 +++
 .../expected/ivm-refresh-insert3.out          |  191 +++
 src/test/isolation/isolation_schedule         |    9 +
 .../isolation/specs/ivm-create-insert.spec    |   47 +
 .../isolation/specs/ivm-create-insert2.spec   |   54 +
 .../isolation/specs/ivm-create-insert3.spec   |   54 +
 .../isolation/specs/ivm-insert-insert.spec    |   62 +
 .../isolation/specs/ivm-insert-insert2.spec   |   62 +
 .../isolation/specs/ivm-insert-insert3.spec   |   62 +
 .../isolation/specs/ivm-refresh-insert.spec   |   46 +
 .../isolation/specs/ivm-refresh-insert2.spec  |   46 +
 .../isolation/specs/ivm-refresh-insert3.spec  |   46 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 22 files changed, 4902 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Wed__1_Jul_2026_00_04_01_+0900_OVSy2WWK_9aByzDJ
Content-Type: text/x-diff;
 name="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v39 7/8] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  | 285 ++++++++
 .../isolation/expected/ivm-create-insert2.out | 305 ++++++++
 .../isolation/expected/ivm-create-insert3.out | 305 ++++++++
 .../isolation/expected/ivm-insert-insert.out  | 497 +++++++++++++
 .../isolation/expected/ivm-insert-insert2.out | 373 ++++++++++
 .../isolation/expected/ivm-insert-insert3.out | 373 ++++++++++
 .../isolation/expected/ivm-refresh-insert.out | 213 ++++++
 .../expected/ivm-refresh-insert2.out          | 191 +++++
 .../expected/ivm-refresh-insert3.out          | 191 +++++
 src/test/isolation/isolation_schedule         |   9 +
 .../isolation/specs/ivm-create-insert.spec    |  47 ++
 .../isolation/specs/ivm-create-insert2.spec   |  54 ++
 .../isolation/specs/ivm-create-insert3.spec   |  54 ++
 .../isolation/specs/ivm-insert-insert.spec    |  62 ++
 .../isolation/specs/ivm-insert-insert2.spec   |  62 ++
 .../isolation/specs/ivm-insert-insert3.spec   |  62 ++
 .../isolation/specs/ivm-refresh-insert.spec   |  46 ++
 .../isolation/specs/ivm-refresh-insert2.spec  |  46 ++
 .../isolation/specs/ivm-refresh-insert3.spec  |  46 ++
 .../regress/expected/incremental_matview.out  | 667 ++++++++++++++++++
 src/test/regress/parallel_schedule            |   1 +
 src/test/regress/sql/incremental_matview.sql  | 407 +++++++++++
 22 files changed, 4296 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..c7fd19fdca3
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,667 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..7313ad82f3e
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,407 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ROLLBACK;
+
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__3_Jul_2026_19_11_16_+0900_CskxSIu_iGcDMEyM
Content-Type: text/x-diff;
 name="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Disposition: attachment;
 filename="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v38 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  |  285 +++++
 .../isolation/expected/ivm-create-insert2.out |  305 +++++
 .../isolation/expected/ivm-create-insert3.out |  305 +++++
 .../isolation/expected/ivm-insert-insert.out  |  497 ++++++++
 .../isolation/expected/ivm-insert-insert2.out |  373 ++++++
 .../isolation/expected/ivm-insert-insert3.out |  373 ++++++
 .../isolation/expected/ivm-refresh-insert.out |  213 ++++
 .../expected/ivm-refresh-insert2.out          |  191 +++
 .../expected/ivm-refresh-insert3.out          |  191 +++
 src/test/isolation/isolation_schedule         |    9 +
 .../isolation/specs/ivm-create-insert.spec    |   47 +
 .../isolation/specs/ivm-create-insert2.spec   |   54 +
 .../isolation/specs/ivm-create-insert3.spec   |   54 +
 .../isolation/specs/ivm-insert-insert.spec    |   62 +
 .../isolation/specs/ivm-insert-insert2.spec   |   62 +
 .../isolation/specs/ivm-insert-insert3.spec   |   62 +
 .../isolation/specs/ivm-refresh-insert.spec   |   46 +
 .../isolation/specs/ivm-refresh-insert2.spec  |   46 +
 .../isolation/specs/ivm-refresh-insert3.spec  |   46 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 22 files changed, 4902 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Wed__1_Jul_2026_00_04_01_+0900_OVSy2WWK_9aByzDJ
Content-Type: text/x-diff;
 name="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v37 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 src/test/isolation/isolation_schedule         |    9 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 4 files changed, 1690 insertions(+)
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index 15c33fad4c5..111fd465207 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -127,3 +127,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__29_May_2026_23_14_17_+0900_Te0o73X2VqYK57Gd
Content-Type: text/x-diff;
 name="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v37 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 src/test/isolation/isolation_schedule         |    9 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 4 files changed, 1690 insertions(+)
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index 15c33fad4c5..111fd465207 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -127,3 +127,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__29_May_2026_23_14_17_+0900_Te0o73X2VqYK57Gd
Content-Type: text/x-diff;
 name="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v38 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  |  285 +++++
 .../isolation/expected/ivm-create-insert2.out |  305 +++++
 .../isolation/expected/ivm-create-insert3.out |  305 +++++
 .../isolation/expected/ivm-insert-insert.out  |  497 ++++++++
 .../isolation/expected/ivm-insert-insert2.out |  373 ++++++
 .../isolation/expected/ivm-insert-insert3.out |  373 ++++++
 .../isolation/expected/ivm-refresh-insert.out |  213 ++++
 .../expected/ivm-refresh-insert2.out          |  191 +++
 .../expected/ivm-refresh-insert3.out          |  191 +++
 src/test/isolation/isolation_schedule         |    9 +
 .../isolation/specs/ivm-create-insert.spec    |   47 +
 .../isolation/specs/ivm-create-insert2.spec   |   54 +
 .../isolation/specs/ivm-create-insert3.spec   |   54 +
 .../isolation/specs/ivm-insert-insert.spec    |   62 +
 .../isolation/specs/ivm-insert-insert2.spec   |   62 +
 .../isolation/specs/ivm-insert-insert3.spec   |   62 +
 .../isolation/specs/ivm-refresh-insert.spec   |   46 +
 .../isolation/specs/ivm-refresh-insert2.spec  |   46 +
 .../isolation/specs/ivm-refresh-insert3.spec  |   46 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 22 files changed, 4902 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Wed__1_Jul_2026_00_04_01_+0900_OVSy2WWK_9aByzDJ
Content-Type: text/x-diff;
 name="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v39 7/8] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  | 285 ++++++++
 .../isolation/expected/ivm-create-insert2.out | 305 ++++++++
 .../isolation/expected/ivm-create-insert3.out | 305 ++++++++
 .../isolation/expected/ivm-insert-insert.out  | 497 +++++++++++++
 .../isolation/expected/ivm-insert-insert2.out | 373 ++++++++++
 .../isolation/expected/ivm-insert-insert3.out | 373 ++++++++++
 .../isolation/expected/ivm-refresh-insert.out | 213 ++++++
 .../expected/ivm-refresh-insert2.out          | 191 +++++
 .../expected/ivm-refresh-insert3.out          | 191 +++++
 src/test/isolation/isolation_schedule         |   9 +
 .../isolation/specs/ivm-create-insert.spec    |  47 ++
 .../isolation/specs/ivm-create-insert2.spec   |  54 ++
 .../isolation/specs/ivm-create-insert3.spec   |  54 ++
 .../isolation/specs/ivm-insert-insert.spec    |  62 ++
 .../isolation/specs/ivm-insert-insert2.spec   |  62 ++
 .../isolation/specs/ivm-insert-insert3.spec   |  62 ++
 .../isolation/specs/ivm-refresh-insert.spec   |  46 ++
 .../isolation/specs/ivm-refresh-insert2.spec  |  46 ++
 .../isolation/specs/ivm-refresh-insert3.spec  |  46 ++
 .../regress/expected/incremental_matview.out  | 667 ++++++++++++++++++
 src/test/regress/parallel_schedule            |   1 +
 src/test/regress/sql/incremental_matview.sql  | 407 +++++++++++
 22 files changed, 4296 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..c7fd19fdca3
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,667 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..7313ad82f3e
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,407 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ROLLBACK;
+
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__3_Jul_2026_19_11_16_+0900_CskxSIu_iGcDMEyM
Content-Type: text/x-diff;
 name="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Disposition: attachment;
 filename="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v39 7/8] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  | 285 ++++++++
 .../isolation/expected/ivm-create-insert2.out | 305 ++++++++
 .../isolation/expected/ivm-create-insert3.out | 305 ++++++++
 .../isolation/expected/ivm-insert-insert.out  | 497 +++++++++++++
 .../isolation/expected/ivm-insert-insert2.out | 373 ++++++++++
 .../isolation/expected/ivm-insert-insert3.out | 373 ++++++++++
 .../isolation/expected/ivm-refresh-insert.out | 213 ++++++
 .../expected/ivm-refresh-insert2.out          | 191 +++++
 .../expected/ivm-refresh-insert3.out          | 191 +++++
 src/test/isolation/isolation_schedule         |   9 +
 .../isolation/specs/ivm-create-insert.spec    |  47 ++
 .../isolation/specs/ivm-create-insert2.spec   |  54 ++
 .../isolation/specs/ivm-create-insert3.spec   |  54 ++
 .../isolation/specs/ivm-insert-insert.spec    |  62 ++
 .../isolation/specs/ivm-insert-insert2.spec   |  62 ++
 .../isolation/specs/ivm-insert-insert3.spec   |  62 ++
 .../isolation/specs/ivm-refresh-insert.spec   |  46 ++
 .../isolation/specs/ivm-refresh-insert2.spec  |  46 ++
 .../isolation/specs/ivm-refresh-insert3.spec  |  46 ++
 .../regress/expected/incremental_matview.out  | 667 ++++++++++++++++++
 src/test/regress/parallel_schedule            |   1 +
 src/test/regress/sql/incremental_matview.sql  | 407 +++++++++++
 22 files changed, 4296 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..c7fd19fdca3
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,667 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..7313ad82f3e
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,407 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ROLLBACK;
+
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__3_Jul_2026_19_11_16_+0900_CskxSIu_iGcDMEyM
Content-Type: text/x-diff;
 name="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Disposition: attachment;
 filename="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v38 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  |  285 +++++
 .../isolation/expected/ivm-create-insert2.out |  305 +++++
 .../isolation/expected/ivm-create-insert3.out |  305 +++++
 .../isolation/expected/ivm-insert-insert.out  |  497 ++++++++
 .../isolation/expected/ivm-insert-insert2.out |  373 ++++++
 .../isolation/expected/ivm-insert-insert3.out |  373 ++++++
 .../isolation/expected/ivm-refresh-insert.out |  213 ++++
 .../expected/ivm-refresh-insert2.out          |  191 +++
 .../expected/ivm-refresh-insert3.out          |  191 +++
 src/test/isolation/isolation_schedule         |    9 +
 .../isolation/specs/ivm-create-insert.spec    |   47 +
 .../isolation/specs/ivm-create-insert2.spec   |   54 +
 .../isolation/specs/ivm-create-insert3.spec   |   54 +
 .../isolation/specs/ivm-insert-insert.spec    |   62 +
 .../isolation/specs/ivm-insert-insert2.spec   |   62 +
 .../isolation/specs/ivm-insert-insert3.spec   |   62 +
 .../isolation/specs/ivm-refresh-insert.spec   |   46 +
 .../isolation/specs/ivm-refresh-insert2.spec  |   46 +
 .../isolation/specs/ivm-refresh-insert3.spec  |   46 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 22 files changed, 4902 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Wed__1_Jul_2026_00_04_01_+0900_OVSy2WWK_9aByzDJ
Content-Type: text/x-diff;
 name="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v37 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 src/test/isolation/isolation_schedule         |    9 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 4 files changed, 1690 insertions(+)
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index 15c33fad4c5..111fd465207 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -127,3 +127,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__29_May_2026_23_14_17_+0900_Te0o73X2VqYK57Gd
Content-Type: text/x-diff;
 name="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v37 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 src/test/isolation/isolation_schedule         |    9 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 4 files changed, 1690 insertions(+)
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index 15c33fad4c5..111fd465207 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -127,3 +127,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__29_May_2026_23_14_17_+0900_Te0o73X2VqYK57Gd
Content-Type: text/x-diff;
 name="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v37 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 src/test/isolation/isolation_schedule         |    9 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 4 files changed, 1690 insertions(+)
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index 15c33fad4c5..111fd465207 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -127,3 +127,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__29_May_2026_23_14_17_+0900_Te0o73X2VqYK57Gd
Content-Type: text/x-diff;
 name="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v38 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  |  285 +++++
 .../isolation/expected/ivm-create-insert2.out |  305 +++++
 .../isolation/expected/ivm-create-insert3.out |  305 +++++
 .../isolation/expected/ivm-insert-insert.out  |  497 ++++++++
 .../isolation/expected/ivm-insert-insert2.out |  373 ++++++
 .../isolation/expected/ivm-insert-insert3.out |  373 ++++++
 .../isolation/expected/ivm-refresh-insert.out |  213 ++++
 .../expected/ivm-refresh-insert2.out          |  191 +++
 .../expected/ivm-refresh-insert3.out          |  191 +++
 src/test/isolation/isolation_schedule         |    9 +
 .../isolation/specs/ivm-create-insert.spec    |   47 +
 .../isolation/specs/ivm-create-insert2.spec   |   54 +
 .../isolation/specs/ivm-create-insert3.spec   |   54 +
 .../isolation/specs/ivm-insert-insert.spec    |   62 +
 .../isolation/specs/ivm-insert-insert2.spec   |   62 +
 .../isolation/specs/ivm-insert-insert3.spec   |   62 +
 .../isolation/specs/ivm-refresh-insert.spec   |   46 +
 .../isolation/specs/ivm-refresh-insert2.spec  |   46 +
 .../isolation/specs/ivm-refresh-insert3.spec  |   46 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 22 files changed, 4902 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Wed__1_Jul_2026_00_04_01_+0900_OVSy2WWK_9aByzDJ
Content-Type: text/x-diff;
 name="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v39 7/8] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  | 285 ++++++++
 .../isolation/expected/ivm-create-insert2.out | 305 ++++++++
 .../isolation/expected/ivm-create-insert3.out | 305 ++++++++
 .../isolation/expected/ivm-insert-insert.out  | 497 +++++++++++++
 .../isolation/expected/ivm-insert-insert2.out | 373 ++++++++++
 .../isolation/expected/ivm-insert-insert3.out | 373 ++++++++++
 .../isolation/expected/ivm-refresh-insert.out | 213 ++++++
 .../expected/ivm-refresh-insert2.out          | 191 +++++
 .../expected/ivm-refresh-insert3.out          | 191 +++++
 src/test/isolation/isolation_schedule         |   9 +
 .../isolation/specs/ivm-create-insert.spec    |  47 ++
 .../isolation/specs/ivm-create-insert2.spec   |  54 ++
 .../isolation/specs/ivm-create-insert3.spec   |  54 ++
 .../isolation/specs/ivm-insert-insert.spec    |  62 ++
 .../isolation/specs/ivm-insert-insert2.spec   |  62 ++
 .../isolation/specs/ivm-insert-insert3.spec   |  62 ++
 .../isolation/specs/ivm-refresh-insert.spec   |  46 ++
 .../isolation/specs/ivm-refresh-insert2.spec  |  46 ++
 .../isolation/specs/ivm-refresh-insert3.spec  |  46 ++
 .../regress/expected/incremental_matview.out  | 667 ++++++++++++++++++
 src/test/regress/parallel_schedule            |   1 +
 src/test/regress/sql/incremental_matview.sql  | 407 +++++++++++
 22 files changed, 4296 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..c7fd19fdca3
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,667 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..7313ad82f3e
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,407 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ROLLBACK;
+
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__3_Jul_2026_19_11_16_+0900_CskxSIu_iGcDMEyM
Content-Type: text/x-diff;
 name="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Disposition: attachment;
 filename="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v39 7/8] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  | 285 ++++++++
 .../isolation/expected/ivm-create-insert2.out | 305 ++++++++
 .../isolation/expected/ivm-create-insert3.out | 305 ++++++++
 .../isolation/expected/ivm-insert-insert.out  | 497 +++++++++++++
 .../isolation/expected/ivm-insert-insert2.out | 373 ++++++++++
 .../isolation/expected/ivm-insert-insert3.out | 373 ++++++++++
 .../isolation/expected/ivm-refresh-insert.out | 213 ++++++
 .../expected/ivm-refresh-insert2.out          | 191 +++++
 .../expected/ivm-refresh-insert3.out          | 191 +++++
 src/test/isolation/isolation_schedule         |   9 +
 .../isolation/specs/ivm-create-insert.spec    |  47 ++
 .../isolation/specs/ivm-create-insert2.spec   |  54 ++
 .../isolation/specs/ivm-create-insert3.spec   |  54 ++
 .../isolation/specs/ivm-insert-insert.spec    |  62 ++
 .../isolation/specs/ivm-insert-insert2.spec   |  62 ++
 .../isolation/specs/ivm-insert-insert3.spec   |  62 ++
 .../isolation/specs/ivm-refresh-insert.spec   |  46 ++
 .../isolation/specs/ivm-refresh-insert2.spec  |  46 ++
 .../isolation/specs/ivm-refresh-insert3.spec  |  46 ++
 .../regress/expected/incremental_matview.out  | 667 ++++++++++++++++++
 src/test/regress/parallel_schedule            |   1 +
 src/test/regress/sql/incremental_matview.sql  | 407 +++++++++++
 22 files changed, 4296 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..c7fd19fdca3
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,667 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..7313ad82f3e
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,407 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ROLLBACK;
+
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__3_Jul_2026_19_11_16_+0900_CskxSIu_iGcDMEyM
Content-Type: text/x-diff;
 name="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Disposition: attachment;
 filename="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v37 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 src/test/isolation/isolation_schedule         |    9 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 4 files changed, 1690 insertions(+)
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index 15c33fad4c5..111fd465207 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -127,3 +127,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__29_May_2026_23_14_17_+0900_Te0o73X2VqYK57Gd
Content-Type: text/x-diff;
 name="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v39 7/8] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  | 285 ++++++++
 .../isolation/expected/ivm-create-insert2.out | 305 ++++++++
 .../isolation/expected/ivm-create-insert3.out | 305 ++++++++
 .../isolation/expected/ivm-insert-insert.out  | 497 +++++++++++++
 .../isolation/expected/ivm-insert-insert2.out | 373 ++++++++++
 .../isolation/expected/ivm-insert-insert3.out | 373 ++++++++++
 .../isolation/expected/ivm-refresh-insert.out | 213 ++++++
 .../expected/ivm-refresh-insert2.out          | 191 +++++
 .../expected/ivm-refresh-insert3.out          | 191 +++++
 src/test/isolation/isolation_schedule         |   9 +
 .../isolation/specs/ivm-create-insert.spec    |  47 ++
 .../isolation/specs/ivm-create-insert2.spec   |  54 ++
 .../isolation/specs/ivm-create-insert3.spec   |  54 ++
 .../isolation/specs/ivm-insert-insert.spec    |  62 ++
 .../isolation/specs/ivm-insert-insert2.spec   |  62 ++
 .../isolation/specs/ivm-insert-insert3.spec   |  62 ++
 .../isolation/specs/ivm-refresh-insert.spec   |  46 ++
 .../isolation/specs/ivm-refresh-insert2.spec  |  46 ++
 .../isolation/specs/ivm-refresh-insert3.spec  |  46 ++
 .../regress/expected/incremental_matview.out  | 667 ++++++++++++++++++
 src/test/regress/parallel_schedule            |   1 +
 src/test/regress/sql/incremental_matview.sql  | 407 +++++++++++
 22 files changed, 4296 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..c7fd19fdca3
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,667 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..7313ad82f3e
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,407 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ROLLBACK;
+
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__3_Jul_2026_19_11_16_+0900_CskxSIu_iGcDMEyM
Content-Type: text/x-diff;
 name="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Disposition: attachment;
 filename="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v39 7/8] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  | 285 ++++++++
 .../isolation/expected/ivm-create-insert2.out | 305 ++++++++
 .../isolation/expected/ivm-create-insert3.out | 305 ++++++++
 .../isolation/expected/ivm-insert-insert.out  | 497 +++++++++++++
 .../isolation/expected/ivm-insert-insert2.out | 373 ++++++++++
 .../isolation/expected/ivm-insert-insert3.out | 373 ++++++++++
 .../isolation/expected/ivm-refresh-insert.out | 213 ++++++
 .../expected/ivm-refresh-insert2.out          | 191 +++++
 .../expected/ivm-refresh-insert3.out          | 191 +++++
 src/test/isolation/isolation_schedule         |   9 +
 .../isolation/specs/ivm-create-insert.spec    |  47 ++
 .../isolation/specs/ivm-create-insert2.spec   |  54 ++
 .../isolation/specs/ivm-create-insert3.spec   |  54 ++
 .../isolation/specs/ivm-insert-insert.spec    |  62 ++
 .../isolation/specs/ivm-insert-insert2.spec   |  62 ++
 .../isolation/specs/ivm-insert-insert3.spec   |  62 ++
 .../isolation/specs/ivm-refresh-insert.spec   |  46 ++
 .../isolation/specs/ivm-refresh-insert2.spec  |  46 ++
 .../isolation/specs/ivm-refresh-insert3.spec  |  46 ++
 .../regress/expected/incremental_matview.out  | 667 ++++++++++++++++++
 src/test/regress/parallel_schedule            |   1 +
 src/test/regress/sql/incremental_matview.sql  | 407 +++++++++++
 22 files changed, 4296 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..c7fd19fdca3
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,667 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..7313ad82f3e
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,407 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ROLLBACK;
+
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__3_Jul_2026_19_11_16_+0900_CskxSIu_iGcDMEyM
Content-Type: text/x-diff;
 name="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Disposition: attachment;
 filename="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v38 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  |  285 +++++
 .../isolation/expected/ivm-create-insert2.out |  305 +++++
 .../isolation/expected/ivm-create-insert3.out |  305 +++++
 .../isolation/expected/ivm-insert-insert.out  |  497 ++++++++
 .../isolation/expected/ivm-insert-insert2.out |  373 ++++++
 .../isolation/expected/ivm-insert-insert3.out |  373 ++++++
 .../isolation/expected/ivm-refresh-insert.out |  213 ++++
 .../expected/ivm-refresh-insert2.out          |  191 +++
 .../expected/ivm-refresh-insert3.out          |  191 +++
 src/test/isolation/isolation_schedule         |    9 +
 .../isolation/specs/ivm-create-insert.spec    |   47 +
 .../isolation/specs/ivm-create-insert2.spec   |   54 +
 .../isolation/specs/ivm-create-insert3.spec   |   54 +
 .../isolation/specs/ivm-insert-insert.spec    |   62 +
 .../isolation/specs/ivm-insert-insert2.spec   |   62 +
 .../isolation/specs/ivm-insert-insert3.spec   |   62 +
 .../isolation/specs/ivm-refresh-insert.spec   |   46 +
 .../isolation/specs/ivm-refresh-insert2.spec  |   46 +
 .../isolation/specs/ivm-refresh-insert3.spec  |   46 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 22 files changed, 4902 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Wed__1_Jul_2026_00_04_01_+0900_OVSy2WWK_9aByzDJ
Content-Type: text/x-diff;
 name="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v37 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 src/test/isolation/isolation_schedule         |    9 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 4 files changed, 1690 insertions(+)
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index 15c33fad4c5..111fd465207 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -127,3 +127,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__29_May_2026_23_14_17_+0900_Te0o73X2VqYK57Gd
Content-Type: text/x-diff;
 name="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v37 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 src/test/isolation/isolation_schedule         |    9 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 4 files changed, 1690 insertions(+)
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index 15c33fad4c5..111fd465207 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -127,3 +127,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__29_May_2026_23_14_17_+0900_Te0o73X2VqYK57Gd
Content-Type: text/x-diff;
 name="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v39 7/8] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  | 285 ++++++++
 .../isolation/expected/ivm-create-insert2.out | 305 ++++++++
 .../isolation/expected/ivm-create-insert3.out | 305 ++++++++
 .../isolation/expected/ivm-insert-insert.out  | 497 +++++++++++++
 .../isolation/expected/ivm-insert-insert2.out | 373 ++++++++++
 .../isolation/expected/ivm-insert-insert3.out | 373 ++++++++++
 .../isolation/expected/ivm-refresh-insert.out | 213 ++++++
 .../expected/ivm-refresh-insert2.out          | 191 +++++
 .../expected/ivm-refresh-insert3.out          | 191 +++++
 src/test/isolation/isolation_schedule         |   9 +
 .../isolation/specs/ivm-create-insert.spec    |  47 ++
 .../isolation/specs/ivm-create-insert2.spec   |  54 ++
 .../isolation/specs/ivm-create-insert3.spec   |  54 ++
 .../isolation/specs/ivm-insert-insert.spec    |  62 ++
 .../isolation/specs/ivm-insert-insert2.spec   |  62 ++
 .../isolation/specs/ivm-insert-insert3.spec   |  62 ++
 .../isolation/specs/ivm-refresh-insert.spec   |  46 ++
 .../isolation/specs/ivm-refresh-insert2.spec  |  46 ++
 .../isolation/specs/ivm-refresh-insert3.spec  |  46 ++
 .../regress/expected/incremental_matview.out  | 667 ++++++++++++++++++
 src/test/regress/parallel_schedule            |   1 +
 src/test/regress/sql/incremental_matview.sql  | 407 +++++++++++
 22 files changed, 4296 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..c7fd19fdca3
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,667 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..7313ad82f3e
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,407 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ROLLBACK;
+
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__3_Jul_2026_19_11_16_+0900_CskxSIu_iGcDMEyM
Content-Type: text/x-diff;
 name="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Disposition: attachment;
 filename="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v39 7/8] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  | 285 ++++++++
 .../isolation/expected/ivm-create-insert2.out | 305 ++++++++
 .../isolation/expected/ivm-create-insert3.out | 305 ++++++++
 .../isolation/expected/ivm-insert-insert.out  | 497 +++++++++++++
 .../isolation/expected/ivm-insert-insert2.out | 373 ++++++++++
 .../isolation/expected/ivm-insert-insert3.out | 373 ++++++++++
 .../isolation/expected/ivm-refresh-insert.out | 213 ++++++
 .../expected/ivm-refresh-insert2.out          | 191 +++++
 .../expected/ivm-refresh-insert3.out          | 191 +++++
 src/test/isolation/isolation_schedule         |   9 +
 .../isolation/specs/ivm-create-insert.spec    |  47 ++
 .../isolation/specs/ivm-create-insert2.spec   |  54 ++
 .../isolation/specs/ivm-create-insert3.spec   |  54 ++
 .../isolation/specs/ivm-insert-insert.spec    |  62 ++
 .../isolation/specs/ivm-insert-insert2.spec   |  62 ++
 .../isolation/specs/ivm-insert-insert3.spec   |  62 ++
 .../isolation/specs/ivm-refresh-insert.spec   |  46 ++
 .../isolation/specs/ivm-refresh-insert2.spec  |  46 ++
 .../isolation/specs/ivm-refresh-insert3.spec  |  46 ++
 .../regress/expected/incremental_matview.out  | 667 ++++++++++++++++++
 src/test/regress/parallel_schedule            |   1 +
 src/test/regress/sql/incremental_matview.sql  | 407 +++++++++++
 22 files changed, 4296 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..c7fd19fdca3
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,667 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..7313ad82f3e
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,407 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ROLLBACK;
+
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__3_Jul_2026_19_11_16_+0900_CskxSIu_iGcDMEyM
Content-Type: text/x-diff;
 name="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Disposition: attachment;
 filename="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v37 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 src/test/isolation/isolation_schedule         |    9 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 4 files changed, 1690 insertions(+)
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index 15c33fad4c5..111fd465207 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -127,3 +127,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__29_May_2026_23_14_17_+0900_Te0o73X2VqYK57Gd
Content-Type: text/x-diff;
 name="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v37 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 src/test/isolation/isolation_schedule         |    9 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 4 files changed, 1690 insertions(+)
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index 15c33fad4c5..111fd465207 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -127,3 +127,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__29_May_2026_23_14_17_+0900_Te0o73X2VqYK57Gd
Content-Type: text/x-diff;
 name="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v37 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 src/test/isolation/isolation_schedule         |    9 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 4 files changed, 1690 insertions(+)
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index 15c33fad4c5..111fd465207 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -127,3 +127,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__29_May_2026_23_14_17_+0900_Te0o73X2VqYK57Gd
Content-Type: text/x-diff;
 name="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v38 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  |  285 +++++
 .../isolation/expected/ivm-create-insert2.out |  305 +++++
 .../isolation/expected/ivm-create-insert3.out |  305 +++++
 .../isolation/expected/ivm-insert-insert.out  |  497 ++++++++
 .../isolation/expected/ivm-insert-insert2.out |  373 ++++++
 .../isolation/expected/ivm-insert-insert3.out |  373 ++++++
 .../isolation/expected/ivm-refresh-insert.out |  213 ++++
 .../expected/ivm-refresh-insert2.out          |  191 +++
 .../expected/ivm-refresh-insert3.out          |  191 +++
 src/test/isolation/isolation_schedule         |    9 +
 .../isolation/specs/ivm-create-insert.spec    |   47 +
 .../isolation/specs/ivm-create-insert2.spec   |   54 +
 .../isolation/specs/ivm-create-insert3.spec   |   54 +
 .../isolation/specs/ivm-insert-insert.spec    |   62 +
 .../isolation/specs/ivm-insert-insert2.spec   |   62 +
 .../isolation/specs/ivm-insert-insert3.spec   |   62 +
 .../isolation/specs/ivm-refresh-insert.spec   |   46 +
 .../isolation/specs/ivm-refresh-insert2.spec  |   46 +
 .../isolation/specs/ivm-refresh-insert3.spec  |   46 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 22 files changed, 4902 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Wed__1_Jul_2026_00_04_01_+0900_OVSy2WWK_9aByzDJ
Content-Type: text/x-diff;
 name="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v37 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 src/test/isolation/isolation_schedule         |    9 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 4 files changed, 1690 insertions(+)
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index 15c33fad4c5..111fd465207 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -127,3 +127,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__29_May_2026_23_14_17_+0900_Te0o73X2VqYK57Gd
Content-Type: text/x-diff;
 name="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v38 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  |  285 +++++
 .../isolation/expected/ivm-create-insert2.out |  305 +++++
 .../isolation/expected/ivm-create-insert3.out |  305 +++++
 .../isolation/expected/ivm-insert-insert.out  |  497 ++++++++
 .../isolation/expected/ivm-insert-insert2.out |  373 ++++++
 .../isolation/expected/ivm-insert-insert3.out |  373 ++++++
 .../isolation/expected/ivm-refresh-insert.out |  213 ++++
 .../expected/ivm-refresh-insert2.out          |  191 +++
 .../expected/ivm-refresh-insert3.out          |  191 +++
 src/test/isolation/isolation_schedule         |    9 +
 .../isolation/specs/ivm-create-insert.spec    |   47 +
 .../isolation/specs/ivm-create-insert2.spec   |   54 +
 .../isolation/specs/ivm-create-insert3.spec   |   54 +
 .../isolation/specs/ivm-insert-insert.spec    |   62 +
 .../isolation/specs/ivm-insert-insert2.spec   |   62 +
 .../isolation/specs/ivm-insert-insert3.spec   |   62 +
 .../isolation/specs/ivm-refresh-insert.spec   |   46 +
 .../isolation/specs/ivm-refresh-insert2.spec  |   46 +
 .../isolation/specs/ivm-refresh-insert3.spec  |   46 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 22 files changed, 4902 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Wed__1_Jul_2026_00_04_01_+0900_OVSy2WWK_9aByzDJ
Content-Type: text/x-diff;
 name="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v39 7/8] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  | 285 ++++++++
 .../isolation/expected/ivm-create-insert2.out | 305 ++++++++
 .../isolation/expected/ivm-create-insert3.out | 305 ++++++++
 .../isolation/expected/ivm-insert-insert.out  | 497 +++++++++++++
 .../isolation/expected/ivm-insert-insert2.out | 373 ++++++++++
 .../isolation/expected/ivm-insert-insert3.out | 373 ++++++++++
 .../isolation/expected/ivm-refresh-insert.out | 213 ++++++
 .../expected/ivm-refresh-insert2.out          | 191 +++++
 .../expected/ivm-refresh-insert3.out          | 191 +++++
 src/test/isolation/isolation_schedule         |   9 +
 .../isolation/specs/ivm-create-insert.spec    |  47 ++
 .../isolation/specs/ivm-create-insert2.spec   |  54 ++
 .../isolation/specs/ivm-create-insert3.spec   |  54 ++
 .../isolation/specs/ivm-insert-insert.spec    |  62 ++
 .../isolation/specs/ivm-insert-insert2.spec   |  62 ++
 .../isolation/specs/ivm-insert-insert3.spec   |  62 ++
 .../isolation/specs/ivm-refresh-insert.spec   |  46 ++
 .../isolation/specs/ivm-refresh-insert2.spec  |  46 ++
 .../isolation/specs/ivm-refresh-insert3.spec  |  46 ++
 .../regress/expected/incremental_matview.out  | 667 ++++++++++++++++++
 src/test/regress/parallel_schedule            |   1 +
 src/test/regress/sql/incremental_matview.sql  | 407 +++++++++++
 22 files changed, 4296 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..c7fd19fdca3
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,667 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..7313ad82f3e
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,407 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ROLLBACK;
+
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__3_Jul_2026_19_11_16_+0900_CskxSIu_iGcDMEyM
Content-Type: text/x-diff;
 name="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Disposition: attachment;
 filename="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v37 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 src/test/isolation/isolation_schedule         |    9 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 4 files changed, 1690 insertions(+)
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index 15c33fad4c5..111fd465207 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -127,3 +127,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__29_May_2026_23_14_17_+0900_Te0o73X2VqYK57Gd
Content-Type: text/x-diff;
 name="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v38 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  |  285 +++++
 .../isolation/expected/ivm-create-insert2.out |  305 +++++
 .../isolation/expected/ivm-create-insert3.out |  305 +++++
 .../isolation/expected/ivm-insert-insert.out  |  497 ++++++++
 .../isolation/expected/ivm-insert-insert2.out |  373 ++++++
 .../isolation/expected/ivm-insert-insert3.out |  373 ++++++
 .../isolation/expected/ivm-refresh-insert.out |  213 ++++
 .../expected/ivm-refresh-insert2.out          |  191 +++
 .../expected/ivm-refresh-insert3.out          |  191 +++
 src/test/isolation/isolation_schedule         |    9 +
 .../isolation/specs/ivm-create-insert.spec    |   47 +
 .../isolation/specs/ivm-create-insert2.spec   |   54 +
 .../isolation/specs/ivm-create-insert3.spec   |   54 +
 .../isolation/specs/ivm-insert-insert.spec    |   62 +
 .../isolation/specs/ivm-insert-insert2.spec   |   62 +
 .../isolation/specs/ivm-insert-insert3.spec   |   62 +
 .../isolation/specs/ivm-refresh-insert.spec   |   46 +
 .../isolation/specs/ivm-refresh-insert2.spec  |   46 +
 .../isolation/specs/ivm-refresh-insert3.spec  |   46 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 22 files changed, 4902 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Wed__1_Jul_2026_00_04_01_+0900_OVSy2WWK_9aByzDJ
Content-Type: text/x-diff;
 name="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v37 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 src/test/isolation/isolation_schedule         |    9 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 4 files changed, 1690 insertions(+)
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index 15c33fad4c5..111fd465207 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -127,3 +127,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__29_May_2026_23_14_17_+0900_Te0o73X2VqYK57Gd
Content-Type: text/x-diff;
 name="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v39 7/8] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  | 285 ++++++++
 .../isolation/expected/ivm-create-insert2.out | 305 ++++++++
 .../isolation/expected/ivm-create-insert3.out | 305 ++++++++
 .../isolation/expected/ivm-insert-insert.out  | 497 +++++++++++++
 .../isolation/expected/ivm-insert-insert2.out | 373 ++++++++++
 .../isolation/expected/ivm-insert-insert3.out | 373 ++++++++++
 .../isolation/expected/ivm-refresh-insert.out | 213 ++++++
 .../expected/ivm-refresh-insert2.out          | 191 +++++
 .../expected/ivm-refresh-insert3.out          | 191 +++++
 src/test/isolation/isolation_schedule         |   9 +
 .../isolation/specs/ivm-create-insert.spec    |  47 ++
 .../isolation/specs/ivm-create-insert2.spec   |  54 ++
 .../isolation/specs/ivm-create-insert3.spec   |  54 ++
 .../isolation/specs/ivm-insert-insert.spec    |  62 ++
 .../isolation/specs/ivm-insert-insert2.spec   |  62 ++
 .../isolation/specs/ivm-insert-insert3.spec   |  62 ++
 .../isolation/specs/ivm-refresh-insert.spec   |  46 ++
 .../isolation/specs/ivm-refresh-insert2.spec  |  46 ++
 .../isolation/specs/ivm-refresh-insert3.spec  |  46 ++
 .../regress/expected/incremental_matview.out  | 667 ++++++++++++++++++
 src/test/regress/parallel_schedule            |   1 +
 src/test/regress/sql/incremental_matview.sql  | 407 +++++++++++
 22 files changed, 4296 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..c7fd19fdca3
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,667 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..7313ad82f3e
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,407 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ROLLBACK;
+
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__3_Jul_2026_19_11_16_+0900_CskxSIu_iGcDMEyM
Content-Type: text/x-diff;
 name="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Disposition: attachment;
 filename="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v38 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  |  285 +++++
 .../isolation/expected/ivm-create-insert2.out |  305 +++++
 .../isolation/expected/ivm-create-insert3.out |  305 +++++
 .../isolation/expected/ivm-insert-insert.out  |  497 ++++++++
 .../isolation/expected/ivm-insert-insert2.out |  373 ++++++
 .../isolation/expected/ivm-insert-insert3.out |  373 ++++++
 .../isolation/expected/ivm-refresh-insert.out |  213 ++++
 .../expected/ivm-refresh-insert2.out          |  191 +++
 .../expected/ivm-refresh-insert3.out          |  191 +++
 src/test/isolation/isolation_schedule         |    9 +
 .../isolation/specs/ivm-create-insert.spec    |   47 +
 .../isolation/specs/ivm-create-insert2.spec   |   54 +
 .../isolation/specs/ivm-create-insert3.spec   |   54 +
 .../isolation/specs/ivm-insert-insert.spec    |   62 +
 .../isolation/specs/ivm-insert-insert2.spec   |   62 +
 .../isolation/specs/ivm-insert-insert3.spec   |   62 +
 .../isolation/specs/ivm-refresh-insert.spec   |   46 +
 .../isolation/specs/ivm-refresh-insert2.spec  |   46 +
 .../isolation/specs/ivm-refresh-insert3.spec  |   46 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 22 files changed, 4902 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Wed__1_Jul_2026_00_04_01_+0900_OVSy2WWK_9aByzDJ
Content-Type: text/x-diff;
 name="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v39 7/8] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  | 285 ++++++++
 .../isolation/expected/ivm-create-insert2.out | 305 ++++++++
 .../isolation/expected/ivm-create-insert3.out | 305 ++++++++
 .../isolation/expected/ivm-insert-insert.out  | 497 +++++++++++++
 .../isolation/expected/ivm-insert-insert2.out | 373 ++++++++++
 .../isolation/expected/ivm-insert-insert3.out | 373 ++++++++++
 .../isolation/expected/ivm-refresh-insert.out | 213 ++++++
 .../expected/ivm-refresh-insert2.out          | 191 +++++
 .../expected/ivm-refresh-insert3.out          | 191 +++++
 src/test/isolation/isolation_schedule         |   9 +
 .../isolation/specs/ivm-create-insert.spec    |  47 ++
 .../isolation/specs/ivm-create-insert2.spec   |  54 ++
 .../isolation/specs/ivm-create-insert3.spec   |  54 ++
 .../isolation/specs/ivm-insert-insert.spec    |  62 ++
 .../isolation/specs/ivm-insert-insert2.spec   |  62 ++
 .../isolation/specs/ivm-insert-insert3.spec   |  62 ++
 .../isolation/specs/ivm-refresh-insert.spec   |  46 ++
 .../isolation/specs/ivm-refresh-insert2.spec  |  46 ++
 .../isolation/specs/ivm-refresh-insert3.spec  |  46 ++
 .../regress/expected/incremental_matview.out  | 667 ++++++++++++++++++
 src/test/regress/parallel_schedule            |   1 +
 src/test/regress/sql/incremental_matview.sql  | 407 +++++++++++
 22 files changed, 4296 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..c7fd19fdca3
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,667 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..7313ad82f3e
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,407 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ROLLBACK;
+
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__3_Jul_2026_19_11_16_+0900_CskxSIu_iGcDMEyM
Content-Type: text/x-diff;
 name="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Disposition: attachment;
 filename="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v38 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  |  285 +++++
 .../isolation/expected/ivm-create-insert2.out |  305 +++++
 .../isolation/expected/ivm-create-insert3.out |  305 +++++
 .../isolation/expected/ivm-insert-insert.out  |  497 ++++++++
 .../isolation/expected/ivm-insert-insert2.out |  373 ++++++
 .../isolation/expected/ivm-insert-insert3.out |  373 ++++++
 .../isolation/expected/ivm-refresh-insert.out |  213 ++++
 .../expected/ivm-refresh-insert2.out          |  191 +++
 .../expected/ivm-refresh-insert3.out          |  191 +++
 src/test/isolation/isolation_schedule         |    9 +
 .../isolation/specs/ivm-create-insert.spec    |   47 +
 .../isolation/specs/ivm-create-insert2.spec   |   54 +
 .../isolation/specs/ivm-create-insert3.spec   |   54 +
 .../isolation/specs/ivm-insert-insert.spec    |   62 +
 .../isolation/specs/ivm-insert-insert2.spec   |   62 +
 .../isolation/specs/ivm-insert-insert3.spec   |   62 +
 .../isolation/specs/ivm-refresh-insert.spec   |   46 +
 .../isolation/specs/ivm-refresh-insert2.spec  |   46 +
 .../isolation/specs/ivm-refresh-insert3.spec  |   46 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 22 files changed, 4902 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Wed__1_Jul_2026_00_04_01_+0900_OVSy2WWK_9aByzDJ
Content-Type: text/x-diff;
 name="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v38 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  |  285 +++++
 .../isolation/expected/ivm-create-insert2.out |  305 +++++
 .../isolation/expected/ivm-create-insert3.out |  305 +++++
 .../isolation/expected/ivm-insert-insert.out  |  497 ++++++++
 .../isolation/expected/ivm-insert-insert2.out |  373 ++++++
 .../isolation/expected/ivm-insert-insert3.out |  373 ++++++
 .../isolation/expected/ivm-refresh-insert.out |  213 ++++
 .../expected/ivm-refresh-insert2.out          |  191 +++
 .../expected/ivm-refresh-insert3.out          |  191 +++
 src/test/isolation/isolation_schedule         |    9 +
 .../isolation/specs/ivm-create-insert.spec    |   47 +
 .../isolation/specs/ivm-create-insert2.spec   |   54 +
 .../isolation/specs/ivm-create-insert3.spec   |   54 +
 .../isolation/specs/ivm-insert-insert.spec    |   62 +
 .../isolation/specs/ivm-insert-insert2.spec   |   62 +
 .../isolation/specs/ivm-insert-insert3.spec   |   62 +
 .../isolation/specs/ivm-refresh-insert.spec   |   46 +
 .../isolation/specs/ivm-refresh-insert2.spec  |   46 +
 .../isolation/specs/ivm-refresh-insert3.spec  |   46 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 22 files changed, 4902 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Wed__1_Jul_2026_00_04_01_+0900_OVSy2WWK_9aByzDJ
Content-Type: text/x-diff;
 name="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v37 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 src/test/isolation/isolation_schedule         |    9 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 4 files changed, 1690 insertions(+)
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index 15c33fad4c5..111fd465207 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -127,3 +127,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__29_May_2026_23_14_17_+0900_Te0o73X2VqYK57Gd
Content-Type: text/x-diff;
 name="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v37-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v38 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  |  285 +++++
 .../isolation/expected/ivm-create-insert2.out |  305 +++++
 .../isolation/expected/ivm-create-insert3.out |  305 +++++
 .../isolation/expected/ivm-insert-insert.out  |  497 ++++++++
 .../isolation/expected/ivm-insert-insert2.out |  373 ++++++
 .../isolation/expected/ivm-insert-insert3.out |  373 ++++++
 .../isolation/expected/ivm-refresh-insert.out |  213 ++++
 .../expected/ivm-refresh-insert2.out          |  191 +++
 .../expected/ivm-refresh-insert3.out          |  191 +++
 src/test/isolation/isolation_schedule         |    9 +
 .../isolation/specs/ivm-create-insert.spec    |   47 +
 .../isolation/specs/ivm-create-insert2.spec   |   54 +
 .../isolation/specs/ivm-create-insert3.spec   |   54 +
 .../isolation/specs/ivm-insert-insert.spec    |   62 +
 .../isolation/specs/ivm-insert-insert2.spec   |   62 +
 .../isolation/specs/ivm-insert-insert3.spec   |   62 +
 .../isolation/specs/ivm-refresh-insert.spec   |   46 +
 .../isolation/specs/ivm-refresh-insert2.spec  |   46 +
 .../isolation/specs/ivm-refresh-insert3.spec  |   46 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 22 files changed, 4902 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Wed__1_Jul_2026_00_04_01_+0900_OVSy2WWK_9aByzDJ
Content-Type: text/x-diff;
 name="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v39 7/8] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  | 285 ++++++++
 .../isolation/expected/ivm-create-insert2.out | 305 ++++++++
 .../isolation/expected/ivm-create-insert3.out | 305 ++++++++
 .../isolation/expected/ivm-insert-insert.out  | 497 +++++++++++++
 .../isolation/expected/ivm-insert-insert2.out | 373 ++++++++++
 .../isolation/expected/ivm-insert-insert3.out | 373 ++++++++++
 .../isolation/expected/ivm-refresh-insert.out | 213 ++++++
 .../expected/ivm-refresh-insert2.out          | 191 +++++
 .../expected/ivm-refresh-insert3.out          | 191 +++++
 src/test/isolation/isolation_schedule         |   9 +
 .../isolation/specs/ivm-create-insert.spec    |  47 ++
 .../isolation/specs/ivm-create-insert2.spec   |  54 ++
 .../isolation/specs/ivm-create-insert3.spec   |  54 ++
 .../isolation/specs/ivm-insert-insert.spec    |  62 ++
 .../isolation/specs/ivm-insert-insert2.spec   |  62 ++
 .../isolation/specs/ivm-insert-insert3.spec   |  62 ++
 .../isolation/specs/ivm-refresh-insert.spec   |  46 ++
 .../isolation/specs/ivm-refresh-insert2.spec  |  46 ++
 .../isolation/specs/ivm-refresh-insert3.spec  |  46 ++
 .../regress/expected/incremental_matview.out  | 667 ++++++++++++++++++
 src/test/regress/parallel_schedule            |   1 +
 src/test/regress/sql/incremental_matview.sql  | 407 +++++++++++
 22 files changed, 4296 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..c7fd19fdca3
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,667 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..7313ad82f3e
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,407 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ROLLBACK;
+
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__3_Jul_2026_19_11_16_+0900_CskxSIu_iGcDMEyM
Content-Type: text/x-diff;
 name="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Disposition: attachment;
 filename="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v39 7/8] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  | 285 ++++++++
 .../isolation/expected/ivm-create-insert2.out | 305 ++++++++
 .../isolation/expected/ivm-create-insert3.out | 305 ++++++++
 .../isolation/expected/ivm-insert-insert.out  | 497 +++++++++++++
 .../isolation/expected/ivm-insert-insert2.out | 373 ++++++++++
 .../isolation/expected/ivm-insert-insert3.out | 373 ++++++++++
 .../isolation/expected/ivm-refresh-insert.out | 213 ++++++
 .../expected/ivm-refresh-insert2.out          | 191 +++++
 .../expected/ivm-refresh-insert3.out          | 191 +++++
 src/test/isolation/isolation_schedule         |   9 +
 .../isolation/specs/ivm-create-insert.spec    |  47 ++
 .../isolation/specs/ivm-create-insert2.spec   |  54 ++
 .../isolation/specs/ivm-create-insert3.spec   |  54 ++
 .../isolation/specs/ivm-insert-insert.spec    |  62 ++
 .../isolation/specs/ivm-insert-insert2.spec   |  62 ++
 .../isolation/specs/ivm-insert-insert3.spec   |  62 ++
 .../isolation/specs/ivm-refresh-insert.spec   |  46 ++
 .../isolation/specs/ivm-refresh-insert2.spec  |  46 ++
 .../isolation/specs/ivm-refresh-insert3.spec  |  46 ++
 .../regress/expected/incremental_matview.out  | 667 ++++++++++++++++++
 src/test/regress/parallel_schedule            |   1 +
 src/test/regress/sql/incremental_matview.sql  | 407 +++++++++++
 22 files changed, 4296 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..c7fd19fdca3
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,667 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..7313ad82f3e
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,407 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ROLLBACK;
+
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__3_Jul_2026_19_11_16_+0900_CskxSIu_iGcDMEyM
Content-Type: text/x-diff;
 name="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Disposition: attachment;
 filename="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v38 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  |  285 +++++
 .../isolation/expected/ivm-create-insert2.out |  305 +++++
 .../isolation/expected/ivm-create-insert3.out |  305 +++++
 .../isolation/expected/ivm-insert-insert.out  |  497 ++++++++
 .../isolation/expected/ivm-insert-insert2.out |  373 ++++++
 .../isolation/expected/ivm-insert-insert3.out |  373 ++++++
 .../isolation/expected/ivm-refresh-insert.out |  213 ++++
 .../expected/ivm-refresh-insert2.out          |  191 +++
 .../expected/ivm-refresh-insert3.out          |  191 +++
 src/test/isolation/isolation_schedule         |    9 +
 .../isolation/specs/ivm-create-insert.spec    |   47 +
 .../isolation/specs/ivm-create-insert2.spec   |   54 +
 .../isolation/specs/ivm-create-insert3.spec   |   54 +
 .../isolation/specs/ivm-insert-insert.spec    |   62 +
 .../isolation/specs/ivm-insert-insert2.spec   |   62 +
 .../isolation/specs/ivm-insert-insert3.spec   |   62 +
 .../isolation/specs/ivm-refresh-insert.spec   |   46 +
 .../isolation/specs/ivm-refresh-insert2.spec  |   46 +
 .../isolation/specs/ivm-refresh-insert3.spec  |   46 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 22 files changed, 4902 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Wed__1_Jul_2026_00_04_01_+0900_OVSy2WWK_9aByzDJ
Content-Type: text/x-diff;
 name="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v38 10/11] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  |  285 +++++
 .../isolation/expected/ivm-create-insert2.out |  305 +++++
 .../isolation/expected/ivm-create-insert3.out |  305 +++++
 .../isolation/expected/ivm-insert-insert.out  |  497 ++++++++
 .../isolation/expected/ivm-insert-insert2.out |  373 ++++++
 .../isolation/expected/ivm-insert-insert3.out |  373 ++++++
 .../isolation/expected/ivm-refresh-insert.out |  213 ++++
 .../expected/ivm-refresh-insert2.out          |  191 +++
 .../expected/ivm-refresh-insert3.out          |  191 +++
 src/test/isolation/isolation_schedule         |    9 +
 .../isolation/specs/ivm-create-insert.spec    |   47 +
 .../isolation/specs/ivm-create-insert2.spec   |   54 +
 .../isolation/specs/ivm-create-insert3.spec   |   54 +
 .../isolation/specs/ivm-insert-insert.spec    |   62 +
 .../isolation/specs/ivm-insert-insert2.spec   |   62 +
 .../isolation/specs/ivm-insert-insert3.spec   |   62 +
 .../isolation/specs/ivm-refresh-insert.spec   |   46 +
 .../isolation/specs/ivm-refresh-insert2.spec  |   46 +
 .../isolation/specs/ivm-refresh-insert3.spec  |   46 +
 .../regress/expected/incremental_matview.out  | 1100 +++++++++++++++++
 src/test/regress/parallel_schedule            |    1 +
 src/test/regress/sql/incremental_matview.sql  |  580 +++++++++
 22 files changed, 4902 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..f215aa88e48
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,1100 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_rename_index" on materialized view "mv_ivm_rename"
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+ERROR:  IVM column can not be renamed
+DROP MATERIALIZED VIEW mv_ivm_rename;
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+NOTICE:  created index "mv_ivm_unique_index" on materialized view "mv_ivm_unique"
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+ERROR:  unique index creation on IVM columns is not supported
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+ERROR:  unique index creation on IVM columns is not supported
+DROP MATERIALIZED VIEW mv_ivm_unique;
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+NOTICE:  created index "mv_ivm_distinct_index" on materialized view "mv_ivm_distinct"
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 | 120 |     2 | 60.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg          
+---+-----+-------+----------------------
+ 1 |  10 |     1 |  10.0000000000000000
+ 2 | 220 |     2 | 110.0000000000000000
+ 3 |  30 |     1 |  30.0000000000000000
+ 4 |  40 |     1 |  40.0000000000000000
+ 5 |  50 |     1 |  50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 |  20 |     1
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ i | sum | count 
+---+-----+-------
+ 1 |  10 |     1
+ 2 | 120 |     2
+ 3 |  30 |     1
+ 4 |  40 |     1
+ 5 |  50 |     1
+(5 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+ sum | count 
+-----+-------
+(0 rows)
+
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ i | sum | count 
+---+-----+-------
+(0 rows)
+
+ROLLBACK;
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 150 |     5 | 30.0000000000000000
+(1 row)
+
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count |         avg         
+-----+-------+---------------------
+ 210 |     6 | 35.0000000000000000
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_group" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ sum | count | avg 
+-----+-------+-----
+     |     0 |    
+(1 row)
+
+ROLLBACK;
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+NOTICE:  created index "mv_ivm_avg_bug_index" on materialized view "mv_ivm_avg_bug"
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     3 |  3.3333333333333333
+ 2 |  80 |     3 | 26.6666666666666667
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ i | sum | count |         avg         
+---+-----+-------+---------------------
+ 1 |  10 |     1 | 10.0000000000000000
+ 2 |  20 |     1 | 20.0000000000000000
+ 3 |  30 |     1 | 30.0000000000000000
+ 4 |  40 |     1 | 40.0000000000000000
+ 5 |  50 |     1 | 50.0000000000000000
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_min_max_index" on materialized view "mv_ivm_min_max"
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  10
+ 2 |  20 |  20
+ 3 |  30 |  30
+ 4 |  40 |  40
+ 5 |  50 |  50
+(5 rows)
+
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  10 |  12
+ 2 |  20 |  22
+ 3 |  30 |  32
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ i | min | max 
+---+-----+-----
+ 1 |  11 |  12
+ 2 |  20 |  22
+ 3 |  30 |  31
+ 4 |  40 |  42
+ 5 |  50 |  52
+(5 rows)
+
+ROLLBACK;
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min_max" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  50
+(1 row)
+
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+   0 |  70
+(1 row)
+
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+  10 |  60
+(1 row)
+
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ min | max 
+-----+-----
+     |    
+(1 row)
+
+ROLLBACK;
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_min" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  10
+(1 row)
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  20
+(1 row)
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ min 
+-----
+  30
+(1 row)
+
+ROLLBACK;
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a | sum  
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+NOTICE:  created index "mv_ivm_agg_index" on materialized view "mv_ivm_agg"
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ a |  b   
+---+------
+ 1 |  110
+ 2 | 2200
+ 3 |  300
+ 4 |   40
+ 5 |   50
+(5 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ERROR:  too many column names were specified
+ROLLBACK;
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 |  30
+   |   3
+(2 rows)
+
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ i | sum 
+---+-----
+ 1 | 300
+   |  30
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+NOTICE:  created index "mv_index" on materialized view "mv"
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   1 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   5
+(1 row)
+
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ i | min | max 
+---+-----+-----
+   |   2 |   4
+(1 row)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT ON is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+ERROR:  aggregate function with FILTER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+ERROR:  aggregate function with DISTINCT arguments is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+ERROR:  aggregate function with ORDER clause is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+ERROR:  GROUPING SETS, ROLLUP, or CUBE clauses is not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  GROUP BY expression not appearing in select list is not supported on incrementally maintainable materialized view
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+ERROR:  expression containing an aggregate in it is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+NOTICE:  created index "mv_idx1_index" on materialized view "mv_idx1"
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+NOTICE:  created index "mv_idx2_index" on materialized view "mv_idx2"
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..2d55c393d6f
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,580 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- rename of IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_rename AS SELECT DISTINCT * FROM mv_base_a;
+ALTER MATERIALIZED VIEW mv_ivm_rename RENAME COLUMN __ivm_count__ TO xxx;
+DROP MATERIALIZED VIEW mv_ivm_rename;
+
+-- unique index on IVM columns
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_unique AS SELECT DISTINCT * FROM mv_base_a;
+CREATE UNIQUE INDEX ON mv_ivm_unique(__ivm_count__);
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__));
+CREATE UNIQUE INDEX ON mv_ivm_unique((__ivm_count__ + 1));
+DROP MATERIALIZED VIEW mv_ivm_unique;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have DISTINCT clause or the duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+SELECT * FROM mv_ivm_distinct ORDER BY 1;
+ROLLBACK;
+
+-- support SUM(), COUNT() and AVG() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+UPDATE mv_base_a SET j = 200 WHERE (i,j) = (2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+DELETE FROM mv_base_a WHERE (i,j) = (2,200);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3,4;
+ROLLBACK;
+
+-- support COUNT(*) aggregate function
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES(2,100);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2,3;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+TRUNCATE mv_base_a;
+SELECT sum, count FROM mv_ivm_agg;
+SELECT i, SUM(j), COUNT(*) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+INSERT INTO mv_base_a VALUES(6,60);
+SELECT * FROM mv_ivm_group ORDER BY 1;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_group ORDER BY 1;
+ROLLBACK;
+
+-- TRUNCATE a base table in aggregate views without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_group AS SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+TRUNCATE mv_base_a;
+SELECT sum, count, avg FROM mv_ivm_group;
+SELECT SUM(j), COUNT(j), AVG(j) FROM mv_base_a;
+ROLLBACK;
+
+-- resolved issue: When use AVG() function and values is indivisible, result of AVG() is incorrect.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_avg_bug AS SELECT i, SUM(j), COUNT(j), AVG(j) FROM mv_base_A GROUP BY i;
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,0),
+  (1,0),
+  (2,30),
+  (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) = (1,0);
+DELETE FROM mv_base_a WHERE (i,j) = (2,30);
+SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT i, MIN(j), MAX(j)  FROM mv_base_a GROUP BY i;
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+INSERT INTO mv_base_a VALUES
+  (1,11), (1,12),
+  (2,21), (2,22),
+  (3,31), (3,32),
+  (4,41), (4,42),
+  (5,51), (5,52);
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32));
+SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
+ROLLBACK;
+
+-- support MIN(), MAX() aggregate functions without GROUP clause
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min_max AS SELECT MIN(j), MAX(j)  FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+INSERT INTO mv_base_a VALUES
+  (0,0), (6,60), (7,70);
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
+SELECT * FROM mv_ivm_min_max;
+DELETE FROM mv_base_a;
+SELECT * FROM mv_ivm_min_max;
+ROLLBACK;
+
+-- Test MIN/MAX after search_path change
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_min AS SELECT MIN(j) FROM mv_base_a;
+SELECT * FROM mv_ivm_min;
+
+CREATE SCHEMA myschema;
+GRANT ALL ON SCHEMA myschema TO public;
+CREATE TABLE myschema.mv_base_a (j int);
+INSERT INTO myschema.mv_base_a VALUES (1);
+
+DELETE FROM mv_base_a WHERE (i,j) = (1,10);
+SELECT * FROM mv_ivm_min;
+
+SET search_path TO myschema,public,pg_catalog;
+DELETE FROM public.mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_min;
+ROLLBACK;
+
+-- aggregate views with column names specified
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
+UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
+DELETE FROM mv_base_a WHERE (i,j) = (3,30);
+SELECT * FROM mv_ivm_agg ORDER BY 1,2;
+ROLLBACK;
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg(a,b,c) AS SELECT i, SUM(j) FROM mv_base_a GROUP BY i;
+ROLLBACK;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (1, 10), (1, 20);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, sum(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = v * 10;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT i, min(v), max(v) FROM base_t GROUP BY i;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 1;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 3;
+SELECT * FROM mv ORDER BY i;
+DELETE FROM base_t WHERE v = 5;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- aggregate function with some options is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm17 AS SELECT COUNT(*) FILTER(WHERE i < 3) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm18 AS SELECT COUNT(DISTINCT i)  FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm19 AS SELECT array_agg(j ORDER BY i DESC) FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm20 AS SELECT i,SUM(j) FROM mv_base_a GROUP BY GROUPING SETS((i),());
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- experssions containing an aggregate is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm30 AS SELECT sum(i)*0.5 FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm31 AS SELECT sum(i)/sum(j) FROM mv_base_a;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- group by: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx1 AS SELECT i, sum(j) FROM base_a GROUP BY i;
+
+--- distinct: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx2 AS SELECT DISTINCT j FROM base_a;
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Wed__1_Jul_2026_00_04_01_+0900_OVSy2WWK_9aByzDJ
Content-Type: text/x-diff;
 name="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v38-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread

* [PATCH v39 7/8] Add regression tests for Incremental View Maintenance
@ 2026-05-29 09:31 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 78+ messages in thread

From: Yugo Nagata @ 2026-05-29 09:31 UTC (permalink / raw)

---
 .../isolation/expected/ivm-create-insert.out  | 285 ++++++++
 .../isolation/expected/ivm-create-insert2.out | 305 ++++++++
 .../isolation/expected/ivm-create-insert3.out | 305 ++++++++
 .../isolation/expected/ivm-insert-insert.out  | 497 +++++++++++++
 .../isolation/expected/ivm-insert-insert2.out | 373 ++++++++++
 .../isolation/expected/ivm-insert-insert3.out | 373 ++++++++++
 .../isolation/expected/ivm-refresh-insert.out | 213 ++++++
 .../expected/ivm-refresh-insert2.out          | 191 +++++
 .../expected/ivm-refresh-insert3.out          | 191 +++++
 src/test/isolation/isolation_schedule         |   9 +
 .../isolation/specs/ivm-create-insert.spec    |  47 ++
 .../isolation/specs/ivm-create-insert2.spec   |  54 ++
 .../isolation/specs/ivm-create-insert3.spec   |  54 ++
 .../isolation/specs/ivm-insert-insert.spec    |  62 ++
 .../isolation/specs/ivm-insert-insert2.spec   |  62 ++
 .../isolation/specs/ivm-insert-insert3.spec   |  62 ++
 .../isolation/specs/ivm-refresh-insert.spec   |  46 ++
 .../isolation/specs/ivm-refresh-insert2.spec  |  46 ++
 .../isolation/specs/ivm-refresh-insert3.spec  |  46 ++
 .../regress/expected/incremental_matview.out  | 667 ++++++++++++++++++
 src/test/regress/parallel_schedule            |   1 +
 src/test/regress/sql/incremental_matview.sql  | 407 +++++++++++
 22 files changed, 4296 insertions(+)
 create mode 100644 src/test/isolation/expected/ivm-create-insert.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-create-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-insert-insert3.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert2.out
 create mode 100644 src/test/isolation/expected/ivm-refresh-insert3.out
 create mode 100644 src/test/isolation/specs/ivm-create-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-create-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-insert-insert3.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert2.spec
 create mode 100644 src/test/isolation/specs/ivm-refresh-insert3.spec
 create mode 100644 src/test/regress/expected/incremental_matview.out
 create mode 100644 src/test/regress/sql/incremental_matview.sql

diff --git a/src/test/isolation/expected/ivm-create-insert.out b/src/test/isolation/expected/ivm-create-insert.out
new file mode 100644
index 00000000000..5da00043aba
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert.out
@@ -0,0 +1,285 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert2.out b/src/test/isolation/expected/ivm-create-insert2.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert2.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-create-insert3.out b/src/test/isolation/expected/ivm-create-insert3.out
new file mode 100644
index 00000000000..907d892c6d4
--- /dev/null
+++ b/src/test/isolation/expected/ivm-create-insert3.out
@@ -0,0 +1,305 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 create s2 insert c1 check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 create s2 c1 insert check2 c2 mv
+step s1: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 create insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert create c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s1 s2 create c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 create c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+ <waiting ...>
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 create check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 create check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+tx1: NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns, or this view does not contain GROUP BY or DISTINCT clause.
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+tx1: WARNING:  inconsistent view can be created in isolation level SERIALIZABLE or REPEATABLE READ
+DETAIL:  The view may not include effects of a concurrent transaction.
+HINT:  The view with incremental maintenance should be created in isolation level READ COMMITTED, or refreshed manually to make sure the view is consistent.
+step create: 
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ng      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert.out b/src/test/isolation/expected/ivm-insert-insert.out
new file mode 100644
index 00000000000..5ca4cfea677
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert.out
@@ -0,0 +1,497 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1; <waiting ...>
+step c1: COMMIT;
+step update2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1; <waiting ...>
+step c2: COMMIT;
+step update1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); <waiting ...>
+step c1: COMMIT;
+step insert2: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); <waiting ...>
+step c2: COMMIT;
+step insert1: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+20|20|200
+20|20|201
+20|21|200
+20|21|201
+21|20|200
+21|20|201
+21|21|200
+21|21|201
+(12 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert2.out b/src/test/isolation/expected/ivm-insert-insert2.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert2.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-insert-insert3.out b/src/test/isolation/expected/ivm-insert-insert3.out
new file mode 100644
index 00000000000..e1c66d4de5e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-insert-insert3.out
@@ -0,0 +1,373 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 update1 s2 update2 c1 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 update1 s2 c1 update2 check2 c2 mv
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step s2: SELECT;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 update2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update2 update1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 update1 c1 update2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+step c1: COMMIT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+11|11|100
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 update1 c2 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 update2 s1 c2 update1 check1 c1 mv
+step s2: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step s1: SELECT;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 update2 c2 update1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step update2: UPDATE b SET j = 111 WHERE i = 1;
+step c2: COMMIT;
+step update1: UPDATE a SET j = 11 WHERE i = 1;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|111
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 insert1 s2 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step s2: SELECT;
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 insert2 c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert2 insert1 c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert1 c1 insert2 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+step c1: COMMIT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+20|20|200
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 insert1 c2 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c2: COMMIT;
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert2 s1 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step s1: SELECT;
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert2 c2 insert1 check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert2: INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201);
+step c2: COMMIT;
+step insert1: INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200);
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv();
+ x| y|  z
+--+--+---
+10|10|100
+10|11|100
+11|10|100
+11|11|100
+21|21|201
+(5 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert.out b/src/test/isolation/expected/ivm-refresh-insert.out
new file mode 100644
index 00000000000..a925938bf1c
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert.out
@@ -0,0 +1,213 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2); <waiting ...>
+step c1: COMMIT;
+step insert: <... completed>
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step check1: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert2.out b/src/test/isolation/expected/ivm-refresh-insert2.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert2.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/expected/ivm-refresh-insert3.out b/src/test/isolation/expected/ivm-refresh-insert3.out
new file mode 100644
index 00000000000..dc1b16ae34e
--- /dev/null
+++ b/src/test/isolation/expected/ivm-refresh-insert3.out
@@ -0,0 +1,191 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1 refresh s2 insert c1 check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 refresh s2 c1 insert check2 c2 mv
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step s2: SELECT;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh insert c1 check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step insert: INSERT INTO a VALUES (2);
+ERROR:  could not obtain lock on materialized view "mv" during incremental maintenance
+step c1: COMMIT;
+step check2: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+(1 row)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 insert refresh c2 check1 c1 mv
+step s1: SELECT;
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s1 s2 refresh c1 insert check2 c2 mv
+step s1: SELECT;
+step s2: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+step c1: COMMIT;
+step insert: INSERT INTO a VALUES (2);
+step check2: SELECT check_mv();
+check_mv
+--------
+ok      
+(1 row)
+
+step c2: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 refresh c2 check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step refresh: REFRESH MATERIALIZED VIEW mv; <waiting ...>
+step c2: COMMIT;
+step refresh: <... completed>
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 insert s1 c2 refresh check1 c1 mv
+step s2: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step s1: SELECT;
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
+
+starting permutation: s2 s1 insert c2 refresh check1 c1 mv
+step s2: SELECT;
+step s1: SELECT;
+step insert: INSERT INTO a VALUES (2);
+step c2: COMMIT;
+step refresh: REFRESH MATERIALIZED VIEW mv;
+ERROR:  the materialized view is incrementally updated in concurrent transaction
+step check1: SELECT check_mv();
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step c1: COMMIT;
+step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
+x|y
+-+-
+1|1
+2|2
+(2 rows)
+
+check_mv
+--------
+ok      
+(1 row)
+
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index b8ebe92553c..6b7e873b370 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -128,3 +128,12 @@ test: matview-write-skew
 test: lock-nowait
 test: for-portion-of
 test: ddl-dependency-locking
+test: ivm-create-insert
+test: ivm-create-insert2
+test: ivm-create-insert3
+test: ivm-insert-insert
+test: ivm-insert-insert2
+test: ivm-insert-insert3
+test: ivm-refresh-insert
+test: ivm-refresh-insert2
+test: ivm-refresh-insert3
diff --git a/src/test/isolation/specs/ivm-create-insert.spec b/src/test/isolation/specs/ivm-create-insert.spec
new file mode 100644
index 00000000000..ccd6fd080a9
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert.spec
@@ -0,0 +1,47 @@
+# Test interaction between concurrent transactions performing
+# create and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert2.spec b/src/test/isolation/specs/ivm-create-insert2.spec
new file mode 100644
index 00000000000..02cec85ae07
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert2.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in REPEATABLE READ isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-create-insert3.spec b/src/test/isolation/specs/ivm-create-insert3.spec
new file mode 100644
index 00000000000..19ce03185a4
--- /dev/null
+++ b/src/test/isolation/specs/ivm-create-insert3.spec
@@ -0,0 +1,54 @@
+# Test interaction between concurrent transactions performing
+# create and insert in SERIALIZABLE isolation level
+#
+# Note:
+# In this isolation level, it is possible that create_immv could
+# create an inconsistent view not including effects of a concurrent
+# transaction. So, an warning message is raised to suggest using it
+# in READ COMMITTED or executing refresh_immv to make sure to
+# make the view contents consistent.
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step create {
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 create s2 insert c1 check2 c2 mv
+permutation s1 create s2 c1 insert check2 c2 mv
+permutation s1 s2 create insert c1 check2 c2 mv
+permutation s1 s2 insert create c2 check1 c1 mv
+permutation s1 s2 create c1 insert check2 c2 mv
+permutation s2 insert s1 create c2 check1 c1 mv
+permutation s2 insert s1 c2 create check1 c1 mv
+permutation s2 s1 insert c2 create check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert.spec b/src/test/isolation/specs/ivm-insert-insert.spec
new file mode 100644
index 00000000000..b8f794ca191
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert2.spec b/src/test/isolation/specs/ivm-insert-insert2.spec
new file mode 100644
index 00000000000..ed086d1ba1e
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert2.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-insert-insert3.spec b/src/test/isolation/specs/ivm-insert-insert3.spec
new file mode 100644
index 00000000000..b18bd121033
--- /dev/null
+++ b/src/test/isolation/specs/ivm-insert-insert3.spec
@@ -0,0 +1,62 @@
+# Test interaction between concurrent transactions performing
+# table modifications in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int, j int);
+	CREATE TABLE b (i int, j int);
+	INSERT INTO a VALUES (1,10);
+	INSERT INTO b VALUES (1,100);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE VIEW v(x,y,z) AS
+		SELECT a1.j, a2.j,b.j FROM a AS a1, a AS a2,b WHERE a1.i = a2.i AND a1.i = b.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+	DROP TABLE b;
+}
+
+session tx1
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step insert1 { INSERT INTO a VALUES (2,20); INSERT INTO b VALUES (2,200); }
+step update1 { UPDATE a SET j = 11 WHERE i = 1; }
+step check1 { SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2,3; SELECT check_mv(); }
+
+session tx2
+setup	{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2 { SELECT; }
+step insert2 { INSERT INTO a VALUES (1,11), (2,21); INSERT INTO b VALUES (2,201); }
+step update2 { UPDATE b SET j = 111 WHERE i = 1; }
+step check2 { SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 update1 s2 update2 c1 check2 c2 mv
+permutation s1 update1 s2 c1 update2 check2 c2 mv
+permutation s1 s2 update1 update2 c1 check2 c2 mv
+permutation s1 s2 update2 update1 c2 check1 c1 mv
+permutation s1 s2 update1 c1 update2 check2 c2 mv
+permutation s2 update2 s1 update1 c2 check1 c1 mv
+permutation s2 update2 s1 c2 update1 check1 c1 mv
+permutation s2 s1 update2 c2 update1 check1 c1 mv
+
+permutation s1 insert1 s2 insert2 c1 check2 c2 mv
+permutation s1 insert1 s2 c1 insert2 check2 c2 mv
+permutation s1 s2 insert1 insert2 c1 check2 c2 mv
+permutation s1 s2 insert2 insert1 c2 check1 c1 mv
+permutation s1 s2 insert1 c1 insert2 check2 c2 mv
+permutation s2 insert2 s1 insert1 c2 check1 c1 mv
+permutation s2 insert2 s1 c2 insert1 check1 c1 mv
+permutation s2 s1 insert2 c2 insert1 check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert.spec b/src/test/isolation/specs/ivm-refresh-insert.spec
new file mode 100644
index 00000000000..d7181251962
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in READ COMMITTED isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert2.spec b/src/test/isolation/specs/ivm-refresh-insert2.spec
new file mode 100644
index 00000000000..f2d1d5013f2
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert2.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in REPEATABLE READ isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/isolation/specs/ivm-refresh-insert3.spec b/src/test/isolation/specs/ivm-refresh-insert3.spec
new file mode 100644
index 00000000000..0ec2b1d1de0
--- /dev/null
+++ b/src/test/isolation/specs/ivm-refresh-insert3.spec
@@ -0,0 +1,46 @@
+# Test interaction between concurrent transactions performing
+# refresh and insert in SERIALIZABLE isolation level
+
+setup
+{
+	CREATE TABLE a (i int);
+	INSERT INTO a VALUES (1);
+	CREATE INCREMENTAL MATERIALIZED VIEW mv(x,y) AS SELECT * FROM a a1, a a2 WHERE a1.i = a2.i;
+	CREATE VIEW v(x,y) AS SELECT * FROM a AS a1, a AS a2 WHERE a1.i = a2.i;
+	CREATE FUNCTION check_mv() RETURNS text AS
+		$$ SELECT CASE WHEN count(*) = 0 THEN 'ok' ELSE 'ng' END
+			FROM ((SELECT * FROM mv EXCEPT ALL SELECT * FROM v) UNION ALL
+				  (SELECT * FROM v EXCEPT ALL SELECT * FROM mv)) v $$ LANGUAGE sql;
+}
+
+teardown
+{
+	DROP FUNCTION check_mv();
+	DROP MATERIALIZED VIEW mv;
+	DROP VIEW v;
+	DROP TABLE a;
+}
+
+session tx1
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s1	{ SELECT; }
+step refresh { REFRESH MATERIALIZED VIEW mv; }
+step check1 {SELECT check_mv();}
+step c1 { COMMIT; }
+step mv { SELECT * FROM mv ORDER BY 1,2; SELECT check_mv(); }
+
+session tx2
+setup		{ BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
+step s2	{ SELECT; }
+step insert { INSERT INTO a VALUES (2); }
+step check2 {SELECT check_mv(); }
+step c2 { COMMIT; }
+
+permutation s1 refresh s2 insert c1 check2 c2 mv
+permutation s1 refresh s2 c1 insert check2 c2 mv
+permutation s1 s2 refresh insert c1 check2 c2 mv
+permutation s1 s2 insert refresh c2 check1 c1 mv
+permutation s1 s2 refresh c1 insert check2 c2 mv
+permutation s2 insert s1 refresh c2 check1 c1 mv
+permutation s2 insert s1 c2 refresh check1 c1 mv
+permutation s2 s1 insert c2 refresh check1 c1 mv
diff --git a/src/test/regress/expected/incremental_matview.out b/src/test/regress/expected/incremental_matview.out
new file mode 100644
index 00000000000..c7fd19fdca3
--- /dev/null
+++ b/src/test/regress/expected/incremental_matview.out
@@ -0,0 +1,667 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ERROR:  materialized view "mv_ivm_1" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+NOTICE:  could not create an index on materialized view "mv_ivm_1" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+    17
+(1 row)
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ count 
+-------
+     1
+(1 row)
+
+ROLLBACK;
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+ 5 | 50 | 105
+(5 rows)
+
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 | 10 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ i | j  |  k  
+---+----+-----
+ 1 |  0 | 101
+ 2 | 20 | 102
+ 3 | 30 | 103
+ 4 | 40 | 104
+(4 rows)
+
+ROLLBACK;
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ i | j | k 
+---+---+---
+(0 rows)
+
+ROLLBACK;
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+NOTICE:  could not create an index on materialized view "mv_ivm_func" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+NOTICE:  could not create an index on materialized view "mv_ivm_no_tbl" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+NOTICE:  could not create an index on materialized view "mv_ivm_duplicate" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 20
+ 30
+ 40
+ 50
+(6 rows)
+
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ j  
+----
+ 10
+ 20
+ 30
+ 40
+ 50
+(5 rows)
+
+ROLLBACK;
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+NOTICE:  could not create an index on materialized view "mv_self" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv_self ORDER BY v1;
+ v1 | v2 
+----+----
+ 10 | 10
+ 20 | 20
+ 30 | 30
+(3 rows)
+
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  30 |  30
+  40 |  40
+ 200 | 200
+(3 rows)
+
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv_self ORDER BY v1;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+ 130 | 130
+ 300 | 300
+(4 rows)
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+ v1  | v2  
+-----+-----
+  50 |  50
+  60 |  60
+  70 |  70
+  70 |  77
+  77 |  70
+  77 |  77
+ 130 | 130
+ 300 | 300
+(8 rows)
+
+ROLLBACK;
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY v1;
+ v1 | v2  
+----+-----
+ 10 | 100
+ 20 | 200
+ 30 | 300
+(3 rows)
+
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+ ?column? 
+----------
+ 
+(1 row)
+
+SELECT * FROM mv ORDER BY v1;
+  v1  | v2  
+------+-----
+   10 | 100
+   11 | 100
+ 1020 | 200
+ 1020 | 222
+(4 rows)
+
+ROLLBACK;
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+NOTICE:  created index "mv_ri_index" on materialized view "mv_ri"
+SELECT * FROM mv_ri ORDER BY i1;
+ i1 | i2 
+----+----
+  1 |  1
+  2 |  2
+  3 |  3
+(3 rows)
+
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ i1 | i2 
+----+----
+  3 |  3
+ 10 | 10
+(2 rows)
+
+ROLLBACK;
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 |   
+(2 rows)
+
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ i | v  
+---+----
+ 1 | 10
+ 2 | 20
+(2 rows)
+
+ROLLBACK;
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+NOTICE:  could not create an index on materialized view "mv" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+(0 rows)
+
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ i 
+---
+ 1
+  
+(2 rows)
+
+ROLLBACK;
+-- IMMV containing user defined type
+BEGIN;
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  return type mytype is only a shell
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+NOTICE:  argument type mytype is only a shell
+LINE 1: CREATE FUNCTION mytype_out(mytype)
+                                   ^
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+NOTICE:  could not create an index on materialized view "mv_mytype" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+ x 
+---
+ 1
+(1 row)
+
+ROLLBACK;
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+ERROR:  OUTER JOIN is not supported on incrementally maintainable materialized view
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+ERROR:  CTE is not supported on incrementally maintainable materialized view
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+ERROR:  system column is not supported on incrementally maintainable materialized view
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+ERROR:  ORDER BY clause is not supported on incrementally maintainable materialized view
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+ERROR:   HAVING clause is not supported on incrementally maintainable materialized view
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+ERROR:  VIEW or MATERIALIZED VIEW is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+ERROR:  subquery is not supported on incrementally maintainable materialized view
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+ERROR:  mutable function is not supported on incrementally maintainable materialized view
+HINT:  functions must be marked IMMUTABLE
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+ERROR:  LIMIT/OFFSET clause is not supported on incrementally maintainable materialized view
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+ERROR:  DISTINCT is not supported on incrementally maintainable materialized view
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+ERROR:  TABLESAMPLE clause is not supported on incrementally maintainable materialized view
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+ERROR:  window functions are not supported on incrementally maintainable materialized view
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ERROR:  inheritance parent is not supported on incrementally maintainable materialized view
+ROLLBACK;
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+ERROR:  UNION/INTERSECT/EXCEPT statements are not supported on incrementally maintainable materialized view
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+ERROR:  empty target list is not supported on incrementally maintainable materialized view
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+ERROR:  FOR UPDATE/SHARE clause is not supported on incrementally maintainable materialized view
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+ERROR:  column name __ivm_count__ is not supported on incrementally maintainable materialized view
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+ERROR:  aggregate function is not supported on incrementally maintainable materialized view
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+ERROR:  VALUES is not supported on incrementally maintainable materialized view
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+NOTICE:  role "regress_ivm_admin" does not exist, skipping
+DROP USER IF EXISTS regress_ivm_user;
+NOTICE:  role "regress_ivm_user" does not exist, skipping
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+NOTICE:  could not create an index on materialized view "ivm_rls" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data |      owner       
+----+------+------------------
+  1 | foo  | regress_ivm_user
+  3 | baz  | regress_ivm_user
+(2 rows)
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+--
+(1 row)
+
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+ id | data  |      owner       
+----+-------+------------------
+  2 | bar   | regress_ivm_user
+  3 | baz   | regress_ivm_user
+  6 | corge | regress_ivm_user
+(3 rows)
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+NOTICE:  could not create an index on materialized view "ivm_rls2" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+RESET SESSION AUTHORIZATION;
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+--
+(1 row)
+
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+ id | data  |      owner       |   num   
+----+-------+------------------+---------
+  2 | bar   | regress_ivm_user | two
+  3 | baz_2 | regress_ivm_user | three_2
+  6 | corge | regress_ivm_user | six
+(3 rows)
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+NOTICE:  could not create an index on materialized view "mv_update_same" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+ i 
+---
+ 2
+(1 row)
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+NOTICE:  created index "mv_self_ref_index" on materialized view "mv_self_ref"
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ a  | b  
+----+----
+ 11 |   
+ 12 | 11
+ 13 | 12
+(3 rows)
+
+ROLLBACK;
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+NOTICE:  created index "mv_idx3_index" on materialized view "mv_idx3"
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+NOTICE:  could not create an index on materialized view "mv_idx4" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+NOTICE:  could not create an index on materialized view "mv_idx5" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+NOTICE:  could not create an index on materialized view "mv_idx6" automatically
+DETAIL:  This target list does not have all the primary key columns. 
+HINT:  Create an index on the materialized view for efficient incremental maintenance.
+ROLLBACK;
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ERROR:  data type json has no default operator class for access method "btree"
+ROLLBACK;
+-- cleanup
+DROP TABLE rls_tbl CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to materialized view ivm_rls
+drop cascades to materialized view ivm_rls2
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+DROP TABLE mv_base_b CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to materialized view mv_ivm_1
+drop cascades to view b_view
+drop cascades to materialized view b_mview
+DROP TABLE mv_base_a CASCADE;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8fa0a6c47fb..7caca5f64fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -77,6 +77,7 @@ test: brin_bloom brin_multi
 # Another group of parallel tests
 # ----------
 test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: incremental_matview
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/sql/incremental_matview.sql b/src/test/regress/sql/incremental_matview.sql
new file mode 100644
index 00000000000..7313ad82f3e
--- /dev/null
+++ b/src/test/regress/sql/incremental_matview.sql
@@ -0,0 +1,407 @@
+-- create a table to use as a basis for views and materialized views in various combinations
+CREATE TABLE mv_base_a (x int, i int, y int, j int);
+CREATE TABLE mv_base_b (x int, i int, y int, k int);
+-- test for base tables with dropped columns
+ALTER TABLE mv_base_a DROP COLUMN x;
+ALTER TABLE mv_base_a DROP COLUMN y;
+ALTER TABLE mv_base_b DROP COLUMN x;
+ALTER TABLE mv_base_b DROP COLUMN y;
+INSERT INTO mv_base_a VALUES
+  (1,10),
+  (2,20),
+  (3,30),
+  (4,40),
+  (5,50);
+INSERT INTO mv_base_b VALUES
+  (1,101),
+  (2,102),
+  (3,103),
+  (4,104);
+
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_1 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) WITH NO DATA;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+REFRESH MATERIALIZED VIEW mv_ivm_1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- REFRESH WITH NO DATA
+BEGIN;
+CREATE FUNCTION dummy_ivm_trigger_func() RETURNS TRIGGER AS $$
+  BEGIN
+    RETURN NULL;
+  END
+$$ language plpgsql;
+
+CREATE CONSTRAINT TRIGGER dummy_ivm_trigger AFTER INSERT
+ON mv_base_a FROM mv_ivm_1 FOR EACH ROW
+EXECUTE PROCEDURE dummy_ivm_trigger_func();
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+
+REFRESH MATERIALIZED VIEW mv_ivm_1 WITH NO DATA;
+
+SELECT COUNT(*)
+FROM pg_depend pd INNER JOIN pg_trigger pt ON pd.objid = pt.oid
+WHERE pd.classid = 'pg_trigger'::regclass AND pd.refobjid = 'mv_ivm_1'::regclass;
+ROLLBACK;
+
+-- immediate maintenance
+BEGIN;
+INSERT INTO mv_base_b VALUES(5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+UPDATE mv_base_a SET j = 0 WHERE i = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+DELETE FROM mv_base_b WHERE (i,k) = (5,105);
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+
+-- DISTINCT not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_distinct AS SELECT DISTINCT * FROM mv_base_a;
+
+-- test for renaming column name to camel style
+BEGIN;
+ALTER TABLE mv_base_a RENAME i TO "I";
+ALTER TABLE mv_base_a RENAME j TO "J";
+UPDATE mv_base_a SET "J" = 0 WHERE "I" = 1;
+SELECT * FROM mv_ivm_1 ORDER BY 1,2,3;
+ROLLBACK;
+
+
+-- TRUNCATE a base table in join views
+BEGIN;
+TRUNCATE mv_base_a;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+BEGIN;
+TRUNCATE mv_base_b;
+SELECT * FROM mv_ivm_1;
+ROLLBACK;
+
+-- some query syntax
+BEGIN;
+CREATE FUNCTION ivm_func() RETURNS int LANGUAGE 'sql'
+       AS 'SELECT 1' IMMUTABLE;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_func AS SELECT * FROM ivm_func();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_no_tbl AS SELECT 1;
+ROLLBACK;
+
+-- result of materialized view have duplicate result.
+BEGIN;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_duplicate AS SELECT j FROM mv_base_a;
+INSERT INTO mv_base_a VALUES(6,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+DELETE FROM mv_base_a WHERE (i,j) = (2,20);
+SELECT * FROM mv_ivm_duplicate ORDER BY 1;
+ROLLBACK;
+
+-- aggregate not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_agg AS SELECT i, SUM(j), COUNT(i), AVG(j) FROM mv_base_a GROUP BY i;
+
+-- support self join view and multiple change on the same table
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1, 10), (2, 20), (3, 30);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self(v1, v2) AS
+ SELECT t1.v, t2.v FROM base_t AS t1 JOIN base_t AS t2 ON t1.i = t2.i;
+SELECT * FROM mv_self ORDER BY v1;
+INSERT INTO base_t VALUES (4,40);
+DELETE FROM base_t WHERE i = 1;
+UPDATE base_t SET v = v*10 WHERE i=2;
+SELECT * FROM mv_self ORDER BY v1;
+WITH
+ ins_t1 AS (INSERT INTO base_t VALUES (5,50) RETURNING 1),
+ ins_t2 AS (INSERT INTO base_t VALUES (6,60) RETURNING 1),
+ upd_t AS (UPDATE base_t SET v = v + 100  RETURNING 1),
+ dlt_t AS (DELETE FROM base_t WHERE i IN (4,5)  RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv_self ORDER BY v1;
+
+--- with sub-transactions
+SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,70);
+RELEASE SAVEPOINT p1;
+INSERT INTO base_t VALUES (7,77);
+SELECT * FROM mv_self ORDER BY v1, v2;
+
+ROLLBACK;
+
+-- support simultaneous table changes
+BEGIN;
+CREATE TABLE base_r (i int, v int);
+CREATE TABLE base_s (i int, v int);
+INSERT INTO base_r VALUES (1, 10), (2, 20), (3, 30);
+INSERT INTO base_s VALUES (1, 100), (2, 200), (3, 300);
+CREATE INCREMENTAL MATERIALIZED VIEW mv(v1, v2) AS
+ SELECT r.v, s.v FROM base_r AS r JOIN base_s AS s USING(i);
+SELECT * FROM mv ORDER BY v1;
+WITH
+ ins_r AS (INSERT INTO base_r VALUES (1,11) RETURNING 1),
+ ins_r2 AS (INSERT INTO base_r VALUES (3,33) RETURNING 1),
+ ins_s AS (INSERT INTO base_s VALUES (2,222) RETURNING 1),
+ upd_r AS (UPDATE base_r SET v = v + 1000 WHERE i = 2 RETURNING 1),
+ dlt_s AS (DELETE FROM base_s WHERE i = 3 RETURNING 1)
+SELECT NULL;
+SELECT * FROM mv ORDER BY v1;
+ROLLBACK;
+
+-- support foreign reference constraints
+BEGIN;
+CREATE TABLE ri1 (i int PRIMARY KEY);
+CREATE TABLE ri2 (i int PRIMARY KEY REFERENCES ri1(i) ON UPDATE CASCADE ON DELETE CASCADE, v int);
+INSERT INTO ri1 VALUES (1),(2),(3);
+INSERT INTO ri2 VALUES (1),(2),(3);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ri(i1, i2) AS
+ SELECT ri1.i, ri2.i FROM ri1 JOIN ri2 USING(i);
+SELECT * FROM mv_ri ORDER BY i1;
+UPDATE ri1 SET i=10 where i=1;
+DELETE FROM ri1 WHERE i=2;
+SELECT * FROM mv_ri ORDER BY i2;
+ROLLBACK;
+
+-- views including NULL
+BEGIN;
+CREATE TABLE base_t (i int, v int);
+INSERT INTO base_t VALUES (1,10),(2, NULL);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+UPDATE base_t SET v = 20 WHERE i = 2;
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+BEGIN;
+CREATE TABLE base_t (i int);
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM base_t;
+SELECT * FROM mv ORDER BY i;
+INSERT INTO base_t VALUES (1),(NULL);
+SELECT * FROM mv ORDER BY i;
+ROLLBACK;
+
+-- IMMV containing user defined type
+BEGIN;
+
+CREATE TYPE mytype;
+CREATE FUNCTION mytype_in(cstring)
+ RETURNS mytype AS 'int4in'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_out(mytype)
+ RETURNS cstring AS 'int4out'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE TYPE mytype (
+ LIKE = int4,
+ INPUT = mytype_in,
+ OUTPUT = mytype_out
+);
+
+CREATE FUNCTION mytype_eq(mytype, mytype)
+ RETURNS bool AS 'int4eq'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_lt(mytype, mytype)
+ RETURNS bool AS 'int4lt'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+CREATE FUNCTION mytype_cmp(mytype, mytype)
+ RETURNS integer AS 'btint4cmp'
+ LANGUAGE INTERNAL STRICT IMMUTABLE;
+
+CREATE OPERATOR = (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_eq);
+CREATE OPERATOR < (
+ leftarg = mytype, rightarg = mytype,
+ procedure = mytype_lt);
+
+CREATE OPERATOR CLASS mytype_ops
+ DEFAULT FOR TYPE mytype USING btree AS
+ OPERATOR        1       <,
+ OPERATOR        3       = ,
+ FUNCTION		1		mytype_cmp(mytype,mytype);
+
+CREATE TABLE t_mytype (x mytype);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_mytype AS
+ SELECT * FROM t_mytype;
+INSERT INTO t_mytype VALUES ('1'::mytype);
+SELECT * FROM mv_mytype;
+
+ROLLBACK;
+
+-- outer join is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv(a,b) AS SELECT a.i, b.i FROM mv_base_a a LEFT JOIN mv_base_b b ON a.i=b.i;
+-- CTE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv AS
+    WITH b AS ( SELECT * FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i;
+-- contain system column
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm01 AS SELECT i,j,xmin FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm02 AS SELECT i,j FROM mv_base_a WHERE xmin = '610';
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT i,j,xmin::text AS x_min FROM mv_base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm06 AS SELECT i,j,xidsend(xmin) AS x_min FROM mv_base_a;
+-- contain subquery
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm03 AS SELECT i,j FROM mv_base_a WHERE i IN (SELECT i FROM mv_base_b WHERE k < 103 );
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm04 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT * FROM mv_base_b) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm05 AS SELECT i,j, (SELECT k FROM mv_base_b b WHERE a.i = b.i) FROM mv_base_a a;
+-- contain ORDER BY
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm07 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) ORDER BY i,j,k;
+-- contain HAVING
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm08 AS SELECT i,j,k FROM mv_base_a a INNER JOIN mv_base_b b USING(i) GROUP BY i,j,k HAVING SUM(i) > 5;
+
+-- contain view or materialized view
+CREATE VIEW b_view AS SELECT i,k FROM mv_base_b;
+CREATE MATERIALIZED VIEW b_mview AS SELECT i,k FROM mv_base_b;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm07 AS SELECT a.i,a.j FROM mv_base_a a,b_view b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm08 AS SELECT a.i,a.j FROM mv_base_a a,b_mview b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm09 AS SELECT a.i,a.j FROM mv_base_a a, (SELECT i, COUNT(*) FROM mv_base_b GROUP BY i) b WHERE a.i = b.i;
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm10 AS SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 5;
+
+-- contain mutable functions
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm12 AS SELECT i,j FROM mv_base_a WHERE i = random()::int;
+
+-- LIMIT/OFFSET is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm13 AS SELECT i,j FROM mv_base_a LIMIT 10 OFFSET 5;
+
+-- DISTINCT ON is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm14 AS SELECT DISTINCT ON(i) i, j FROM mv_base_a;
+
+-- TABLESAMPLE clause is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm15 AS SELECT i, j FROM mv_base_a TABLESAMPLE SYSTEM(50);
+
+-- window functions are not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm16 AS SELECT *, cume_dist() OVER (ORDER BY i) AS rank FROM mv_base_a;
+
+-- inheritance parent is not supported
+BEGIN;
+CREATE TABLE parent (i int, v int);
+CREATE TABLE child_a(options text) INHERITS(parent);
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm21 AS SELECT * FROM parent;
+ROLLBACK;
+
+-- UNION statement is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm22 AS SELECT i,j FROM mv_base_a UNION ALL SELECT i,k FROM mv_base_b;;
+
+-- empty target list is not allowed with IVM
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm25 AS SELECT FROM mv_base_a;
+
+-- FOR UPDATE/SHARE is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm26 AS SELECT i,j FROM mv_base_a FOR UPDATE;
+
+-- tartget list cannot contain ivm column that start with '__ivm'
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm28 AS SELECT i AS "__ivm_count__" FROM mv_base_a;
+
+-- expressions specified in GROUP BY must appear in the target list.
+CREATE INCREMENTAL MATERIALIZED VIEW  mv_ivm29 AS SELECT COUNT(i) FROM mv_base_a GROUP BY i;
+
+-- VALUES is not supported
+CREATE INCREMENTAL MATERIALIZED VIEW mv_ivm_only_values1 AS values(1);
+
+-- views containing base tables with Row Level Security
+DROP USER IF EXISTS regress_ivm_admin;
+DROP USER IF EXISTS regress_ivm_user;
+CREATE USER regress_ivm_admin;
+CREATE USER regress_ivm_user;
+
+--- create a table with RLS
+SET SESSION AUTHORIZATION regress_ivm_admin;
+CREATE TABLE rls_tbl(id int, data text, owner name);
+INSERT INTO rls_tbl VALUES
+  (1,'foo','regress_ivm_user'),
+  (2,'bar','postgres');
+CREATE TABLE num_tbl(id int, num text);
+INSERT INTO num_tbl VALUES
+  (1,'one'),
+  (2,'two'),
+  (3,'three'),
+  (4,'four'),
+  (5,'five'),
+  (6,'six');
+
+--- Users can access only their own rows
+CREATE POLICY rls_tbl_policy ON rls_tbl FOR SELECT TO PUBLIC USING(owner = current_user);
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT ALL on rls_tbl TO PUBLIC;
+GRANT ALL on num_tbl TO PUBLIC;
+
+--- create a view owned by regress_ivm_user
+SET SESSION AUTHORIZATION regress_ivm_user;
+
+CREATE INCREMENTAL MATERIALIZED VIEW  ivm_rls AS SELECT * FROM rls_tbl;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+RESET SESSION AUTHORIZATION;
+
+--- inserts rows owned by different users
+INSERT INTO rls_tbl VALUES
+  (3,'baz','regress_ivm_user'),
+  (4,'qux','postgres');
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+--- combination of diffent kinds of commands
+WITH
+ i AS (INSERT INTO rls_tbl VALUES(5,'quux','postgres'), (6,'corge','regress_ivm_user')),
+ u AS (UPDATE rls_tbl SET owner = 'postgres' WHERE id = 1),
+ u2 AS (UPDATE rls_tbl SET owner = 'regress_ivm_user' WHERE id = 2)
+SELECT;
+SELECT id, data, owner FROM ivm_rls ORDER BY 1,2,3;
+
+---
+SET SESSION AUTHORIZATION regress_ivm_user;
+CREATE INCREMENTAL MATERIALIZED VIEW ivm_rls2 AS SELECT * FROM rls_tbl JOIN num_tbl USING(id);
+RESET SESSION AUTHORIZATION;
+
+WITH
+ x AS (UPDATE rls_tbl SET data = data || '_2' where id in (3,4)),
+ y AS (UPDATE num_tbl SET num = num || '_2' where id in (3,4))
+SELECT;
+SELECT * FROM ivm_rls2 ORDER BY 1,2,3;
+
+-- trigger updating the same table
+BEGIN;
+CREATE TABLE tbl_update_same (i int);
+CREATE FUNCTION func_update_same() RETURNS TRIGGER AS
+ $$ BEGIN UPDATE tbl_update_same SET i = i + 1; RETURN NEW; END; $$
+ LANGUAGE plpgsql;
+CREATE TRIGGER trig_update_same AFTER INSERT ON tbl_update_same FOR EACH ROW
+ EXECUTE FUNCTION func_update_same();
+CREATE INCREMENTAL MATERIALIZED VIEW mv_update_same AS SELECT * FROM tbl_update_same;
+INSERT INTO tbl_update_same VALUES (1);
+SELECT * FROM mv_update_same;
+
+-- self-referential FKs
+CREATE TABLE tbl_self_ref (a int primary key,
+						   b int references tbl_self_ref(a) ON UPDATE CASCADE);
+INSERT INTO tbl_self_ref VALUES (1, null), (2, 1), (3, 2);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_self_ref AS SELECT * FROM tbl_self_ref;
+UPDATE tbl_self_ref set a = a + 10;
+SELECT * FROM mv_self_ref ORDER BY a;
+ROLLBACK;
+
+-- automatic index creation
+BEGIN;
+CREATE TABLE base_a (i int primary key, j int);
+CREATE TABLE base_b (i int primary key, j int);
+
+--- with all pkey columns: create an index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx3(i_a, i_b) AS SELECT a.i, b.i FROM base_a a, base_b b;
+
+--- missing some pkey columns: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx4 AS SELECT j FROM base_a;
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx5 AS SELECT a.i, b.j FROM base_a a, base_b b;
+
+--- with set-returning function: no index
+CREATE INCREMENTAL MATERIALIZED VIEW mv_idx6 AS SELECT i FROM base_a, generate_series(1,10);
+
+ROLLBACK;
+
+-- type that doesn't have default operator class for access method btree
+BEGIN;
+CREATE TABLE table_json (j json);
+CREATE INCREMENTAL MATERIALIZED VIEW mv_json AS SELECT * from table_json;
+ROLLBACK;
+
+-- cleanup
+
+DROP TABLE rls_tbl CASCADE;
+DROP TABLE num_tbl CASCADE;
+DROP USER regress_ivm_user;
+DROP USER regress_ivm_admin;
+
+DROP TABLE mv_base_b CASCADE;
+DROP TABLE mv_base_a CASCADE;
-- 
2.43.0


--Multipart=_Fri__3_Jul_2026_19_11_16_+0900_CskxSIu_iGcDMEyM
Content-Type: text/x-diff;
 name="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Disposition: attachment;
 filename="v39-0006-Add-Incremental-View-Maintenance-support.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 78+ messages in thread


end of thread, other threads:[~2026-05-29 09:31 UTC | newest]

Thread overview: 78+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2021-03-10 02:11 [PATCH v28 10/11] Add regression tests for Incremental View Maintenance Takuma Hoshiai <[email protected]>
2021-03-10 02:11 [PATCH v31 10/11] Add regression tests for Incremental View Maintenance Takuma Hoshiai <[email protected]>
2021-03-10 02:11 [PATCH v23 09/15] Add regression tests for Incremental View Maintenance Takuma Hoshiai <[email protected]>
2021-03-10 02:11 [PATCH v29 10/11] Add regression tests for Incremental View Maintenance Takuma Hoshiai <[email protected]>
2021-03-10 02:11 [PATCH v27 8/9] Add regression tests for Incremental View Maintenance Takuma Hoshiai <[email protected]>
2021-03-10 02:11 [PATCH v26 09/10] Add regression tests for Incremental View Maintenance Takuma Hoshiai <[email protected]>
2021-03-10 02:11 [PATCH v24 09/15] Add regression tests for Incremental View Maintenance Takuma Hoshiai <[email protected]>
2021-03-10 02:11 [PATCH v34 10/11] Add regression tests for Incremental View Maintenance Takuma Hoshiai <[email protected]>
2021-03-10 02:11 [PATCH v25 09/15] Add regression tests for Incremental View Maintenance Takuma Hoshiai <[email protected]>
2021-03-10 02:11 [PATCH v32 10/11] Add regression tests for Incremental View Maintenance Takuma Hoshiai <[email protected]>
2021-03-10 02:11 [PATCH v33 10/11] Add regression tests for Incremental View Maintenance Takuma Hoshiai <[email protected]>
2021-03-10 02:11 [PATCH v24 09/15] Add regression tests for Incremental View Maintenance Takuma Hoshiai <[email protected]>
2021-03-10 02:11 [PATCH v30 10/11] Add regression tests for Incremental View Maintenance Takuma Hoshiai <[email protected]>
2021-03-10 02:11 [PATCH v27 8/9] Add regression tests for Incremental View Maintenance Takuma Hoshiai <[email protected]>
2021-03-10 02:11 [PATCH v29 10/11] Add regression tests for Incremental View Maintenance Takuma Hoshiai <[email protected]>
2023-09-22 04:53 [PATCH v7 4/7] Row pattern recognition patch (executor). Tatsuo Ishii <[email protected]>
2026-05-29 09:31 [PATCH v37 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v39 7/8] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v39 7/8] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v38 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v38 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v39 7/8] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v38 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v39 7/8] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v37 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v39 7/8] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v37 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v38 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v37 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v37 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v37 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v38 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v38 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v38 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v39 7/8] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v38 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v37 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v37 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v38 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v39 7/8] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v39 7/8] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v38 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v37 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v37 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v37 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v38 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v39 7/8] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v39 7/8] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v37 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v39 7/8] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v39 7/8] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v38 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v37 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v37 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v39 7/8] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v39 7/8] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v37 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v37 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v37 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v38 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v37 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v38 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v39 7/8] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v37 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v38 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v37 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v39 7/8] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v38 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v39 7/8] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v38 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v38 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v37 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v38 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v39 7/8] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v39 7/8] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v38 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v38 10/11] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>
2026-05-29 09:31 [PATCH v39 7/8] Add regression tests for Incremental View Maintenance Yugo Nagata <[email protected]>

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox